È possibile usare std :: string in un constexpr?


175

Utilizzando C ++ 11, Ubuntu 14.04, toolchain predefinito GCC .

Questo codice ha esito negativo:

constexpr std::string constString = "constString";

errore: il tipo 'const string {aka const std :: basic_string}' della variabile constexpr 'constString' non è letterale ... perché ... 'std :: basic_string' ha un distruttore non banale

È possibile utilizzare std::stringin un constexpr? (apparentemente no ...) In tal caso, come? Esiste un modo alternativo di usare una stringa di caratteri in un constexpr?


2
std::stringnon è un tipo letterale
Piotr Skotnicki il

7
@PiotrS - la domanda dice che ...
Vector il

4
@Vector ti ho chiesto a cosa serve constexpr o perché vuoi std::stringessere constexpr? ci sono diverse implementazioni di stringhe in fase di compilazione su SO. che senso ha chiedere se è possibile creare un tipo non letterale constexpr se si comprende un messaggio di errore e si sa che solo i tipi letterali possono essere resi constexpr? inoltre ci sono diversi motivi per cui si potrebbe desiderare di avere un'istanza constexpr, quindi ti suggerisco di chiarire la tua domanda
Piotr Skotnicki,

2
Sì come @PiotrS. detto, ci sono constexprimplementazioni di stringhe là fuori. std::stringnon è uno di questi.
dieci,

3
@PiotrS - Esistono diverse implementazioni di stringhe in fase di compilazione su SO - OK, grazie, capito. Questa non è un'opzione per me, ma risponde alla mia domanda: nessun modo std :: string funzionerà. Come ho osservato per dieci volte, mi chiedevo se ci fosse un modo per usare std :: string in modo che funzionasse. Ci sono molti trucchi di cui di certo non sono a conoscenza.
Vettore

Risposte:


167

No, e il tuo compilatore ti ha già fornito una spiegazione completa.

Ma potresti farlo:

constexpr char constString[] = "constString";

In fase di esecuzione, questo può essere utilizzato per costruire un std::stringquando necessario.


78
Perché no constexpr auto constString = "constString";? Non c'è bisogno di usare quella brutta sintassi dell'array ;-)
stefan,

80
Nel contesto di questa domanda, è più chiaro. Il mio punto è su quali tipi di stringa puoi scegliere. char[]è più dettagliato / chiaro rispetto a autoquando sto cercando di enfatizzare il tipo di dati da utilizzare.
dieci,

7
@tenfour Giusto, è un buon punto. Immagino di essere a volte un po 'troppo concentrato sull'uso auto;-)
stefan,

1
@FelixDombek no, ma con c ++ 17 potresti usarlo a constexpr auto s = "c"sv;causa dell'introduzione distring_view
che

6
Ha senso creare un array di caratteri in quel contesto? Se lo usi per costruire una stringa, verrà comunque copiato. Qual è la differenza tra il passaggio letterale al costruttore della stringa e il passaggio di un array costexpr ad esso?
KjMag

169

A partire da C ++ 20 , sì.

A partire da C ++ 17 , puoi usare string_view:

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

A string_viewè un stringoggetto simile che funge da riferimento immutabile e non proprietario a qualsiasi sequenza di charoggetti.


6
Essere consapevoli del fatto che ogni volta che si passa questa costante a una funzione che prende const std::string&una nuova std :: string deve essere costruita. Questo di solito è l'opposto di ciò che uno aveva in mente quando si creava una costante. Pertanto, tendo a dire che questa non è una buona idea. Almeno devi stare attento.
Rambo Ramon

29
@RamboRamon string_viewnon è implicitamente convertibile in string, quindi c'è poco pericolo di costruire accidentalmente a stringda a string_view. Al contrario, char const* è implicitamente convertibile in string, quindi l'utilizzo string_viewè in realtà più sicuro in questo senso.
Joseph Thomson,

4
Grazie per il chiarimento. Sono totalmente d'accordo e in effetti ho dimenticato che string_viewnon è implicitamente convertibile in string. IMO il problema che ho sollevato è ancora valido ma non si applica string_viewspecificamente. In effetti, come hai detto, è ancora più sicuro al riguardo.
Rambo Ramon

5
Sarebbe bello se questa risposta dicesse di più su ciò che string_viewè, anziché solo un link.
eric,

23

C ++ 20 aggiungerà constexprstringhe e vettori

Apparentemente la seguente proposta è stata accettata : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0980r0.pdf e aggiunge costruttori come:

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

oltre alle versioni constexpr di tutti / la maggior parte dei metodi.

Non esiste supporto a partire da GCC 9.1.0, la seguente compilazione non riesce:

#include <string>

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

con:

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

con errore:

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

std::vectordiscusso: Impossibile creare constexpr std :: vector

Testato su Ubuntu 19.04.


19

Poiché il problema è il distruttore non banale, quindi se il distruttore viene rimosso dal std::string, è possibile definire constexprun'istanza di quel tipo. Come questo

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

18
Questo è fondamentalmente ciò che c ++ 17 string_viewè, tranne che string_viewti dà la maggior parte delle funzionalità che conoscistd::string
che
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.