Czy można użyć std :: string w constexpr?

175

Używając C ++ 11, Ubuntu 14.04, domyślnego łańcucha narzędzi GCC .

Ten kod nie działa:

constexpr std::string constString = "constString";

błąd: typ 'const string {aka const std :: basic_string}' zmiennej constexpr 'constString' nie jest dosłowny ... ponieważ ... 'std :: basic_string' ma nietrywialny destruktor

Czy można użyć std::stringw constexpr? (najwyraźniej nie ...) Jeśli tak, to jak? Czy istnieje alternatywny sposób użycia ciągu znaków w constexpr?

Wektor
źródło
2
std::stringnie jest typem dosłownym
Piotr Skotnicki
7
@PiotrS - pytanie mówi, że ...
Vector
4
@Vector czy zapytałem cię, do czego służy constexpr lub dlaczego chcesz std::stringbyć constexpr? istnieje kilka implementacji ciągu znaków czasu kompilacji w SO. Jaki jest sens w pytaniu, czy możesz utworzyć nieliteralny typ constexpr, jeśli rozumiesz komunikat o błędzie i wiesz, że tylko typy literalne mogą być konstruowane jako constexpr? Jest też kilka powodów, dla których warto mieć instancję constexpr, więc proponuję wyjaśnić swoje pytanie
Piotr Skotnicki
2
Tak, jak @PiotrS. powiedział, że istnieją constexprimplementacje stringów. std::stringnie jest jednym z nich.
tenfour
3
@PiotrS - istnieje kilka implementacji stringów w czasie kompilacji na SO - OK, dziękuję, zrozumiałem. To nie jest opcja dla mnie, ale odpowiada na moje pytanie: nie ma mowy, że std :: string nie zadziała. Jak zwróciłem uwagę na tenfour, zastanawiałem się, czy istnieje sposób na użycie std :: string w sposób, który zadziała. Jest wiele sztuczek, których na pewno nie jestem świadomy.
Vector,

Odpowiedzi:

167

Nie, a Twój kompilator już udzielił Ci wyczerpujących wyjaśnień.

Ale możesz to zrobić:

constexpr char constString[] = "constString";

W czasie wykonywania można to wykorzystać do skonstruowania pliku w std::stringrazie potrzeby.

tenfour
źródło
78
Dlaczego nie constexpr auto constString = "constString";? Nie ma potrzeby używania tej brzydkiej składni tablicowej ;-)
stefan
80
W kontekście tego pytania jest to jaśniejsze. Chodzi mi o to, z jakich typów ciągów można wybierać. char[]jest bardziej szczegółowy / wyraźny niż autowtedy, gdy próbuję podkreślić typ danych do użycia.
tenfour
7
@tenfour Dobrze, to dobra uwaga. Myślę, że czasami jestem trochę zbyt skupiony na używaniu auto;-)
stefan
1
@FelixDombek nie, ale z c ++ 17 można by użyć constexpr auto s = "c"sv;ze względu na wprowadzeniestring_view
które
6
Czy w tym kontekście ma sens konstruowanie tablicy znaków? Jeśli użyjesz go do skonstruowania łańcucha, i tak zostanie on skopiowany. Jaka jest różnica między przekazaniem literału do konstruktora łańcucha a przekazaniem do niego takiej tablicy constexpr?
KjMag,
167

Od C ++ 20 , tak.

Od C ++ 17 możesz używać string_view:

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

A string_viewjest stringpodobnym do obiektu obiektem, który działa jako niezmienne, nieposiadające właściciela odniesienie do dowolnej sekwencji charobiektów.

Joseph Thomson
źródło
6
Należy pamiętać, że za każdym razem, gdy przekazujesz tę stałą do funkcji pobierającej const std::string&nowy std :: string, należy skonstruować. Zwykle jest to przeciwieństwo tego, co mieliśmy na myśli, tworząc stałą. Dlatego zwykle mówię, że to nie jest dobry pomysł. Przynajmniej musisz być ostrożny.
Rambo Ramon
29
@RamboRamon string_viewnie jest niejawnie konwertowane na string, więc istnieje niewielkie ryzyko przypadkowego skonstruowania a stringz pliku string_view. I na odwrót, char const* jest niejawnie zamienialny na string, więc używanie string_viewjest w tym sensie bezpieczniejsze.
Joseph Thomson
4
Dziękuję za wyjaśnienie. Całkowicie się zgadzam i rzeczywiście zapomniałem, że string_viewnie można tego domyślnie zamienić na string. IMO problem, który poruszyłem, jest nadal aktualny, ale nie dotyczy string_viewkonkretnie. W rzeczywistości, jak wspomniałeś, pod tym względem jest jeszcze bezpieczniej.
Rambo Ramon
5
Byłoby wspaniale, gdyby ta odpowiedź mówiła więcej o tym string_view, co jest, zamiast tylko linku.
eric
22

C ++ 20 doda constexprciągi i wektory

Następująca propozycja została najwyraźniej zaakceptowana : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0980r0.pdf i dodaje konstruktory takie jak:

// 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;

oprócz wersji constexpr wszystkich / większości metod.

Nie ma wsparcia od GCC 9.1.0, następujące elementy nie mogą się skompilować:

#include <string>

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

z:

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

z błędem:

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

std::vectoromówione w: Cannot create constexpr std :: vector

Testowane w Ubuntu 19.04.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
źródło
19

Ponieważ problemem jest nietrywialny destruktor, więc jeśli destruktor zostanie usunięty z elementu std::string, możliwe jest zdefiniowanie constexprinstancji tego typu. Lubię to

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
źródło
18
Jest to w zasadzie co c ++ 17 string_viewjest, oprócz tego, że string_viewdaje większość funkcji, które znasz zstd::string
wich