¿Es posible usar std :: string en un constexpr?

175

Usando C ++ 11, Ubuntu 14.04, cadena de herramientas predeterminada de GCC .

Este código falla:

constexpr std::string constString = "constString";

error: el tipo 'const string {aka const std :: basic_string}' de la variable constexpr 'constString' no es literal ... porque ... 'std :: basic_string' tiene un destructor no trivial

¿Es posible usar std::stringen un constexpr? (aparentemente no ...) Si es así, ¿cómo? ¿Hay alguna forma alternativa de usar una cadena de caracteres en un constexpr?

Vector
fuente
2
std::stringno es un tipo literal
Piotr Skotnicki
77
@PiotrS - la pregunta dice que ...
Vector
44
@Vector, ¿te pregunté para qué sirve el constexpr o por qué quieres std::stringser constexpr? Hay varias implementaciones de cadenas en tiempo de compilación en SO. ¿Cuál es el punto de preguntar si puede hacer un constexpr de tipo no literal si comprende el mensaje de error y sabe que solo los tipos literales se pueden hacer constexpr? así que hay varias razones por las cuales uno puede querer tener una instancia constexpr, por lo que sugiero a aclarar su pregunta
Piotr Skotnicki
2
Sí como @PiotrS. dicho, hay constexprimplementaciones de cadenas por ahí. std::stringNo es uno de ellos.
diez
3
@PiotrS - hay varias implementaciones de cadenas en tiempo de compilación en SO - OK, gracias, entendido. Esa no es una opción para mí, pero responde a mi pregunta: de ninguna manera std :: string funcionará. Mientras comentaba a diez cuatro, me preguntaba si había una manera de usar std :: string de la manera que funcionaría. Hay muchos trucos que ciertamente no conozco.
Vector

Respuestas:

167

No, y tu compilador ya te dio una explicación completa.

Pero podrías hacer esto:

constexpr char constString[] = "constString";

En tiempo de ejecución, esto se puede utilizar para construir un std::stringcuando sea necesario.

diez cuatro
fuente
78
¿Por qué no constexpr auto constString = "constString";? No es necesario usar esa sintaxis de matriz fea ;-)
stefan
80
En el contexto de esta pregunta, es más claro. Mi punto es sobre qué tipos de cadenas puede elegir. char[]es más detallado / claro que autocuando intento enfatizar el tipo de datos a usar.
diez
77
@tenfour Correcto, ese es un buen punto. Creo que a veces estoy demasiado concentrado en usar auto;-)
stefan
1
@FelixDombek no, pero con c ++ 17 podría usar constexpr auto s = "c"sv;debido a la introducción destring_view
que
66
¿Tiene sentido constexpr una matriz de caracteres en ese contexto? Si lo usa para construir una cadena, se copiará de todos modos. ¿Cuál es la diferencia entre pasar literal al constructor de la cadena y pasarle una matriz constexpr?
KjMag
169

A partir de C ++ 20 , sí.

A partir de C ++ 17 , puede usar string_view:

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

A string_viewes un stringobjeto similar que actúa como una referencia inmutable y no propietaria de cualquier secuencia de charobjetos.

Joseph Thomson
fuente
66
Tenga en cuenta que siempre que pase esta constante a una función que tome const std::string&una nueva cadena std :: debe construirse. Eso suele ser lo contrario de lo que uno tenía en mente al crear una constante. Por lo tanto, tiendo a decir que esta no es una buena idea. Al menos tienes que tener cuidado.
Rambo Ramon el
29
@RamboRamon string_viewno es implícitamente convertible a string, por lo que hay poco peligro de construir accidentalmente a stringpartir de a string_view. Por el contrario, char const* es convertible implícitamente a string, por lo que el uso string_viewes realmente más seguro en este sentido.
Joseph Thomson
44
Gracias por la aclaración. Estoy totalmente de acuerdo y de hecho olvidé que string_viewno es implícitamente convertible a string. En mi opinión, el problema que mencioné sigue siendo válido, pero no se aplica string_viewespecíficamente. De hecho, como mencionó, es aún más seguro en ese sentido.
Rambo Ramon
55
Sería genial si esta respuesta dijera más sobre lo que string_viewes, en lugar de solo un enlace.
Eric
23

C ++ 20 agregará constexprcadenas y vectores

Al parecer, la siguiente propuesta ha sido aceptada : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0980r0.pdf y agrega constructores 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;

Además de las versiones constexpr de todos / la mayoría de los métodos.

No hay soporte a partir de GCC 9.1.0, lo siguiente no se compila:

#include <string>

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

con:

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

con error:

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

std::vectordiscutido en: No se puede crear constexpr std :: vector

Probado en Ubuntu 19.04.

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

Como el problema es el destructor no trivial, si el destructor se elimina del std::string, es posible definir una constexprinstancia de ese tipo. Me gusta esto

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
fuente
18
Esto es básicamente lo que es C ++ 17 string_view, excepto que string_viewle brinda la mayor parte de la funcionalidad que conocestd::string
que