É possível usar std :: string em um constexpr?

175

Usando C ++ 11, Ubuntu 14.04, cadeia de ferramentas padrão do GCC .

Este código falha:

constexpr std::string constString = "constString";

erro: o tipo 'const string {aka const std :: basic_string}' da variável constexpr 'constString' não é literal ... porque ... 'std :: basic_string' possui um destruidor não trivial

É possível usar std::stringem um constexpr? (aparentemente não ...) Se sim, como? Existe uma maneira alternativa de usar uma cadeia de caracteres em um constexpr?

Vetor
fonte
2
std::stringnão é um tipo literal #
Piotr Skotnicki
7
@PiotrS - a pergunta diz que ...
Vector
4
@ Vector eu perguntei para que serve o constexpr ou por que você quer std::stringser constexpr? existem várias implementações de string em tempo de compilação no SO. qual é o sentido de perguntar se é possível criar um tipo não literal constexpr se você entende a mensagem de erro e sabe que apenas tipos literais podem ser constexpr? assim há várias razões pelas quais se pode querer ter uma instância constexpr, então eu sugiro que você esclarecer sua pergunta
Piotr Skotnicki
2
Sim como @PiotrS. dito, existem constexprimplementações de strings por aí. std::stringnão é um deles.
tenfour
3
@PiotrS - existem várias implementações de strings em tempo de compilação no SO - OK, obrigado, entendi. Isso não é uma opção para mim, mas responde à minha pergunta: de nenhuma maneira std :: string funcionará. Como observei no décimo quarto, fiquei imaginando se havia uma maneira de usar std :: string da maneira que funcionaria. Existem muitos truques dos quais eu certamente não estou ciente.
Vector

Respostas:

167

Não, e seu compilador já lhe deu uma explicação abrangente.

Mas você pode fazer isso:

constexpr char constString[] = "constString";

Em tempo de execução, isso pode ser usado para construir um std::stringquando necessário.

dez quatro
fonte
78
Por que não constexpr auto constString = "constString";? Não há necessidade de usar essa sintaxe de matriz feio ;-)
Stefan
80
No contexto desta questão, é mais claro. Meu argumento é sobre quais tipos de string você pode escolher. char[]é mais detalhado / claro do que autoquando estou tentando enfatizar o tipo de dados a ser usado.
tenfour
7
@tenfour Certo, esse é um bom argumento. Acho que estou às vezes um pouco demasiado centrada sobre o uso auto;-)
Stefan
1
@FelixDombek não, mas com o c ++ 17 você pode usar constexpr auto s = "c"sv;devido à introdução destring_view
que
6
Faz sentido consprender uma matriz de caracteres nesse contexto? Se você usá-lo para construir uma sequência, ela será copiada de qualquer maneira. Qual é a diferença entre passar literal para o construtor da string e passar uma matriz constexpr para ela?
KjMag
169

A partir do C ++ 20 , sim.

A partir do C ++ 17 , você pode usar string_view:

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

A string_viewé um stringobjeto parecido que age como uma referência imutável e não proprietária de qualquer sequência de charobjetos.

Joseph Thomson
fonte
6
Esteja ciente de que sempre que você passa essa constante para uma função, é necessário criar const std::string&uma nova std :: string. Isso geralmente é o oposto do que se tinha em mente ao criar uma constante. Portanto, costumo dizer que essa não é uma boa ideia. Pelo menos você tem que ter cuidado.
Rambo Ramon
29
O @RamboRamon string_viewnão é implicitamente conversível em string, portanto, há pouco risco de construir acidentalmente a stringde a string_view. Por outro lado, char const* é implicitamente conversível em string, portanto, o uso string_viewé realmente mais seguro nesse sentido.
Joseph Thomson
4
Obrigado pelo esclarecimento. Eu concordo totalmente e realmente esqueci que string_viewnão é implicitamente conversível string. OMI, o problema que levantei ainda é válido, mas não se aplica string_viewespecificamente. De fato, como você mencionou, é ainda mais seguro nesse sentido.
Rambo Ramon
5
Seria ótimo se essa resposta dissesse mais sobre o que string_viewé, em vez de apenas um link.
eric
23

C ++ 20 adicionará constexprstrings e vetores

Aparentemente, a seguinte proposta foi aceita : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0980r0.pdf e adiciona construtores como:

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

além das versões constexpr de todos / a maioria dos métodos.

Não há suporte no GCC 9.1.0, o seguinte falha ao compilar:

#include <string>

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

com:

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

com erro:

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

std::vectordiscutido em: Não é possível criar constexpr std :: vector

Testado no Ubuntu 19.04.

Ciro Santilli adicionou uma nova foto
fonte
19

Como o problema é o destruidor não trivial, portanto, se o destruidor for removido do std::string, é possível definir uma constexprinstância desse tipo. Como isso

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
fonte
18
Isso é basicamente o que é o c ++ 17 string_view, exceto que string_viewfornece a maior parte das funcionalidades que você conhecestd::string
que,