Est-il possible d'utiliser std :: string dans une constexpr?

175

Utilisation de C ++ 11, Ubuntu 14.04, la chaîne d'outils par défaut de GCC .

Ce code échoue:

constexpr std::string constString = "constString";

erreur: le type 'const string {aka const std :: basic_string}' de la variable constexpr 'constString' n'est pas littéral ... parce que ... 'std :: basic_string' a un destructeur non trivial

Est-il possible d'utiliser std::stringdans un constexpr? (apparemment pas ...) Si oui, comment? Y at - il une autre façon d'utiliser une chaîne de caractères dans un constexpr?

Vecteur
la source
2
std::stringn'est pas un type littéral
Piotr Skotnicki
7
@PiotrS - la question dit que ...
Vecteur
4
@Vector vous ai-je demandé à quoi sert constexpr ou pourquoi voulez-vous std::stringêtre constexpr? il existe plusieurs implémentations de chaînes au moment de la compilation sur SO. quel est l'intérêt de demander si vous pouvez créer un type non littéral constexpr si vous comprenez le message d'erreur et savez que seuls les types littéraux peuvent être créés constexpr? De plus, il y a plusieurs raisons pour lesquelles on peut vouloir avoir une instance constexpr, donc je vous suggère de clarifier votre question
Piotr Skotnicki
2
Oui comme @PiotrS. dit, il existe constexprdes implémentations de chaînes. std::stringn'en fait pas partie.
tenfour
3
@PiotrS - il existe plusieurs implémentations de chaînes au moment de la compilation sur SO - OK, merci, compris. Ce n'est pas une option pour moi mais cela répond à ma question: aucun moyen que std :: string ne fonctionne. Comme je l'ai fait remarquer à Tenfour, je me demandais s'il y avait un moyen d'utiliser std :: string d'une manière qui fonctionnerait. Il existe de nombreuses astuces dont je ne suis certainement pas au courant.
Vecteur

Réponses:

167

Non, et votre compilateur vous a déjà donné une explication complète.

Mais vous pouvez faire ceci:

constexpr char constString[] = "constString";

Au moment de l'exécution, cela peut être utilisé pour construire un std::stringfichier.

dix quatre
la source
78
Pourquoi pas constexpr auto constString = "constString";? Pas besoin d'utiliser cette vilaine syntaxe de tableau ;-)
stefan
80
Dans le contexte de cette question, c'est plus clair. Mon point est de savoir quels types de chaînes vous pouvez choisir. char[]est plus verbeux / clair que autolorsque j'essaie de mettre l'accent sur le type de données à utiliser.
tenfour
7
@tenfour Oui, c'est un bon point. Je suppose que je suis parfois un peu trop concentré sur l'utilisation auto;-)
stefan
1
@FelixDombek non, mais avec c ++ 17, vous pourriez utiliser en constexpr auto s = "c"sv;raison de l'introduction destring_view
qui
6
Est-il judicieux de constexpr un tableau de caractères dans ce contexte? Si vous l'utilisez pour construire une chaîne, elle sera quand même copiée. Quelle est la différence entre passer un littéral au constructeur de la chaîne et lui passer un tel tableau constexpr?
KjMag
169

À partir de C ++ 20 , oui.

À partir de C ++ 17 , vous pouvez utiliser string_view:

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

A string_viewest un stringobjet semblable à celui qui agit comme une référence immuable et non propriétaire à toute séquence d' charobjets.

Joseph Thomson
la source
6
Sachez que chaque fois que vous passez cette constante à une fonction prenant const std::string&un nouveau std :: string doit être construit. C'est généralement le contraire de ce que l'on avait en tête lors de la création d'une constante. Par conséquent, j'ai tendance à dire que ce n'est pas une bonne idée. Au moins, vous devez être prudent.
Rambo Ramon
29
@RamboRamon string_viewn'est pas implicitement convertible en string, il y a donc peu de risque de construire accidentellement un à stringpartir d'un fichier string_view. Inversement, char const* est implicitement convertible en string, donc l'utilisation string_viewest en fait plus sûre dans ce sens.
Joseph Thomson
4
Merci pour la clarification. Je suis totalement d'accord et j'ai en effet oublié que ce string_viewn'est pas implicitement convertible en string. OMI, le problème que j'ai soulevé est toujours valable mais ne s'applique pas string_viewspécifiquement. En fait, comme vous l'avez mentionné, c'est encore plus sûr à cet égard.
Rambo Ramon
5
Ce serait formidable si cette réponse en disait plus sur ce que string_viewc'est, au lieu d'un simple lien.
eric
23

C ++ 20 ajoutera des constexprchaînes et des vecteurs

La proposition suivante a apparemment été acceptée : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0980r0.pdf et elle ajoute des constructeurs tels que:

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

en plus des versions constexpr de toutes / la plupart des méthodes.

Il n'y a pas de support à partir de GCC 9.1.0, la compilation suivante échoue:

#include <string>

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

avec:

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

avec erreur:

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

std::vectordiscuté à: Impossible de créer constexpr std :: vector

Testé dans Ubuntu 19.04.

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

Puisque le problème est le destructeur non trivial, donc si le destructeur est supprimé du std::string, il est possible de définir une constexprinstance de ce type. Comme ça

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
la source
18
Ceci est essentiellement ce que c ++ 17 string_viewest, à l' exception que string_viewvous donne la plupart des fonctionnalités que vous savez destd::string
Wich