É 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?


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.


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.


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.


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

18
Isso é basicamente o que é o c ++ 17 string_view, exceto que string_viewfornece a maior parte das funcionalidades que você conhecestd::string
— que,
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.