Ser capaz de crear y manipular cadenas durante el tiempo de compilación en C ++ tiene varias aplicaciones útiles. Aunque es posible crear cadenas de tiempo de compilación en C ++, el proceso es muy engorroso, ya que la cadena debe declararse como una secuencia de caracteres variada, p. Ej.
using str = sequence<'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'>;
Las operaciones como la concatenación de cadenas, la extracción de subcadenas y muchas otras se pueden implementar fácilmente como operaciones en secuencias de caracteres. ¿Es posible declarar cadenas en tiempo de compilación más convenientemente? Si no, ¿hay una propuesta en los trabajos que permitiría una conveniente declaración de cadenas en tiempo de compilación?
Por qué fallan los enfoques existentes
Idealmente, nos gustaría poder declarar cadenas de tiempo de compilación de la siguiente manera:
// Approach 1
using str1 = sequence<"Hello, world!">;
o, usando literales definidos por el usuario,
// Approach 2
constexpr auto str2 = "Hello, world!"_s;
donde decltype(str2)
tendria un constexpr
constructor. Es posible implementar una versión más desordenada del enfoque 1, aprovechando el hecho de que puede hacer lo siguiente:
template <unsigned Size, const char Array[Size]>
struct foo;
Sin embargo, la matriz necesitaría tener un enlace externo, por lo que para que el enfoque 1 funcione, tendríamos que escribir algo como esto:
/* Implementation of array to sequence goes here. */
constexpr const char str[] = "Hello, world!";
int main()
{
using s = string<13, str>;
return 0;
}
No hace falta decir que esto es muy inconveniente. Enfoque 2 en realidad no es posible implementar. Si declaramos un constexpr
operador literal ( ), ¿cómo especificaríamos el tipo de retorno? Como necesitamos que el operador devuelva una secuencia de caracteres variada, deberíamos usar el const char*
parámetro para especificar el tipo de retorno:
constexpr auto
operator"" _s(const char* s, size_t n) -> /* Some metafunction using `s` */
Esto da como resultado un error de compilación, porque s
no es un constexpr
. Intentar solucionar esto haciendo lo siguiente no ayuda mucho.
template <char... Ts>
constexpr sequence<Ts...> operator"" _s() { return {}; }
El estándar dicta que este formulario de operador literal específico está reservado para los tipos enteros y de coma flotante. Mientras 123_s
funcionaría, abc_s
no lo haría. ¿Qué pasa si abandonamos por completo los literales definidos por el usuario y solo usamos una constexpr
función regular ?
template <unsigned Size>
constexpr auto
string(const char (&array)[Size]) -> /* Some metafunction using `array` */
Como antes, nos encontramos con el problema de que la matriz, ahora un parámetro para la constexpr
función, ya no es un constexpr
tipo.
Creo que debería ser posible definir una macro de preprocesador en C que tome una cadena y el tamaño de la cadena como argumentos, y devuelva una secuencia que consta de los caracteres en la cadena (usando BOOST_PP_FOR
, stringificación, subíndices de matriz y similares). Sin embargo, no tengo el tiempo (o suficiente interés) para implementar tal macro =)
constexpr
funciones e inicializar matrices (por lo tanto, concat, substr, etc.).
constexpr
cadenas se pueden analizar durante el tiempo de compilación, de modo que puede tomar diferentes rutas de código según los resultados. Esencialmente, puede crear EDL dentro de C ++; Las aplicaciones son bastante ilimitadas.