Apakah mungkin menggunakan std :: string dalam constexpr?

175

Menggunakan C ++ 11, Ubuntu 14.04, GCC toolchain default .

Kode ini gagal:

constexpr std::string constString = "constString";

error: tipe 'const string {alias const std :: basic_string}' dari variabel constexpr 'constString' tidak literal ... karena ... 'std :: basic_string' memiliki destruktor non-sepele

Apakah mungkin untuk digunakan std::stringdalam constexpr? (ternyata tidak ...) Jika demikian, bagaimana? Apakah ada cara alternatif untuk menggunakan string karakter dalam constexpr?

Vektor
sumber
2
std::stringbukan tipe literal
Piotr Skotnicki
7
@PiotrS - pertanyaannya mengatakan bahwa ...
Vector
4
@ Vektor apakah saya bertanya kepada Anda untuk apa constexpr atau mengapa Anda ingin std::stringmenjadi constexpr? ada beberapa implementasi string kompilasi-waktu pada SO. apa gunanya bertanya apakah Anda dapat membuat constexpr tipe non-literal jika Anda memahami pesan kesalahan dan tahu hanya tipe literal yang dapat dibuat constexpr? juga ada beberapa alasan mengapa seseorang mungkin ingin memiliki instance constexpr, jadi saya sarankan Anda mengklarifikasi pertanyaan Anda
Piotr Skotnicki
2
Ya sebagai @PiotrS. kata, ada constexprimplementasi string di luar sana. std::stringbukan salah satu dari mereka.
tenfour
3
@PiotrS - ada beberapa implementasi string waktu kompilasi pada SO - OK, terima kasih, mengerti. Itu bukan pilihan bagi saya tetapi menjawab pertanyaan saya: tidak mungkin std :: string akan berfungsi. Seperti yang saya katakan pada tenfour, saya bertanya-tanya apakah ada cara untuk menggunakan std :: string dengan cara yang bisa digunakan. Ada banyak trik yang tentu saja tidak saya sadari.
Vektor

Jawaban:

167

Tidak, dan kompiler Anda sudah memberi Anda penjelasan yang komprehensif.

Tetapi Anda bisa melakukan ini:

constexpr char constString[] = "constString";

Saat runtime, ini dapat digunakan untuk membangun std::stringketika dibutuhkan.

sepuluh empat
sumber
78
Mengapa tidak constexpr auto constString = "constString";? Tidak perlu menggunakan sintaks array jelek ;-)
stefan
80
Dalam konteks pertanyaan ini, lebih jelas. Maksud saya adalah tentang jenis string yang dapat Anda pilih. char[]lebih verbose / jelas daripada autoketika saya mencoba untuk menekankan tipe data yang digunakan.
Tenfour
7
@tenfour Benar, itu poin yang bagus. Saya kira saya kadang-kadang agak terlalu fokus menggunakan auto;-)
Stefan
1
@FelixDombek tidak, tetapi dengan c ++ 17 Anda dapat menggunakan constexpr auto s = "c"sv;karena pengenalanstring_view
yang
6
Apakah masuk akal untuk membuat array char dalam konteks itu? Jika Anda menggunakannya untuk membuat string, itu tetap akan disalin. Apa perbedaan antara meneruskan literal ke konstruktor string dan meneruskan array constexpr ke sana?
KjMag
169

Pada C ++ 20 , ya.

Pada C ++ 17 , Anda dapat menggunakan string_view:

constexpr std::string_view sv = "hello, world";

A string_viewadalah stringobjek seperti-yang bertindak sebagai referensi yang tidak berubah dan tidak memiliki urutan charobjek apa pun .

Joseph Thomson
sumber
6
Ketahuilah bahwa setiap kali Anda meneruskan konstanta ini ke fungsi yang mengambil const std::string&string std :: baru harus dibangun. Itu biasanya kebalikan dari apa yang ada dalam pikiran ketika membuat konstanta. Karena itu, saya cenderung mengatakan bahwa ini bukan ide yang baik. Setidaknya kamu harus hati-hati.
Rambo Ramon
29
@RamboRamon string_viewtidak dapat dikonversi secara implisit string, jadi ada sedikit bahaya jika tidak sengaja membangun stringdari string_view. Sebaliknya, char const* adalah implisit dikonversi ke string, sehingga menggunakan string_viewsebenarnya lebih aman dalam pengertian ini.
Joseph Thomson
4
Terimakasih atas klarifikasinya. Saya sepenuhnya setuju dan memang lupa bahwa string_viewsecara implisit tidak dapat dikonversi string. IMO masalah yang saya kemukakan masih valid tetapi tidak berlaku string_viewsecara khusus. Bahkan, seperti yang Anda sebutkan, itu bahkan lebih aman dalam hal itu.
Rambo Ramon
5
Akan lebih bagus jika jawaban ini mengatakan lebih banyak tentang apa string_viewitu, bukan hanya tautan.
eric
23

C ++ 20 akan menambahkan constexprstring dan vektor

Proposal berikut tampaknya telah diterima : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0980r0.pdf dan proposal itu menambahkan konstruktor seperti:

// 20.3.2.2, construct/copy/destroy
constexpr
basic_string() noexcept(noexcept(Allocator())) : basic_string(Allocator()) { }
constexpr
explicit basic_string(const Allocator& a) noexcept;
constexpr
basic_string(const basic_string& str);
constexpr
basic_string(basic_string&& str) noexcept;

selain versi constexpr dari semua / sebagian besar metode.

Tidak ada dukungan pada GCC 9.1.0, yang berikut gagal dikompilasi:

#include <string>

int main() {
    constexpr std::string s("abc");
}

dengan:

g++-9 -std=c++2a main.cpp

dengan kesalahan:

error: the type const string {aka const std::__cxx11::basic_string<char>’} of constexpr variable s is not literal

std::vectordibahas di: Tidak dapat membuat constexpr std :: vector

Diuji di Ubuntu 19,04.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
19

Karena masalahnya adalah destruktor non-sepele jadi jika destruktor dihapus dari std::string, mungkin untuk menentukan constexprcontoh dari tipe itu. Seperti ini

struct constexpr_str {
    char const* str;
    std::size_t size;

    // can only construct from a char[] literal
    template <std::size_t N>
    constexpr constexpr_str(char const (&s)[N])
        : str(s)
        , size(N - 1) // not count the trailing nul
    {}
};

int main()
{
    constexpr constexpr_str s("constString");

    // its .size is a constexpr
    std::array<int, s.size> a;
    return 0;
}
neuront
sumber
18
Ini pada dasarnya adalah apa c ++ 17 string_view, kecuali yang string_viewmemberi Anda sebagian besar fungsi yang Anda tahustd::string
yang