Ser capaz de criar e manipular seqüências de caracteres durante o tempo de compilação em C ++ tem vários aplicativos úteis. Embora seja possível criar seqüências de tempo de compilação em C ++, o processo é muito complicado, pois a cadeia precisa ser declarada como uma sequência variável de caracteres, por exemplo,
using str = sequence<'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'>;
Operações como concatenação de strings, extração de substring e muitas outras, podem ser facilmente implementadas como operações em seqüências de caracteres. É possível declarar seqüências de caracteres em tempo de compilação de forma mais conveniente? Caso contrário, existe uma proposta em andamento que permita uma declaração conveniente de seqüências de caracteres em tempo de compilação?
Por que as abordagens existentes falham
Idealmente, gostaríamos de poder declarar seqüências de caracteres em tempo de compilação da seguinte maneira:
// Approach 1
using str1 = sequence<"Hello, world!">;
ou, usando literais definidos pelo usuário,
// Approach 2
constexpr auto str2 = "Hello, world!"_s;
onde decltype(str2)
teria um constexpr
construtor. É possível implementar uma versão mais confusa da abordagem 1, aproveitando o fato de que você pode fazer o seguinte:
template <unsigned Size, const char Array[Size]>
struct foo;
No entanto, a matriz precisaria ter ligação externa; portanto, para que a abordagem 1 funcione, teríamos que escrever algo como isto:
/* Implementation of array to sequence goes here. */
constexpr const char str[] = "Hello, world!";
int main()
{
using s = string<13, str>;
return 0;
}
Escusado será dizer que isso é muito inconveniente. A abordagem 2 não é realmente possível de implementar. Se declarássemos um constexpr
operador literal ( ), como especificaríamos o tipo de retorno? Como precisamos que o operador retorne uma sequência variável de caracteres, precisamos usar o const char*
parâmetro para especificar o tipo de retorno:
constexpr auto
operator"" _s(const char* s, size_t n) -> /* Some metafunction using `s` */
Isso resulta em um erro de compilação, porque s
não é um constexpr
. Tentar contornar isso fazendo o seguinte não ajuda muito.
template <char... Ts>
constexpr sequence<Ts...> operator"" _s() { return {}; }
O padrão determina que esse formulário literal específico do operador seja reservado para tipos inteiros e de ponto flutuante. Enquanto 123_s
iria funcionar, abc_s
não iria. E se abandonarmos literais definidos pelo usuário por completo e usarmos uma constexpr
função regular ?
template <unsigned Size>
constexpr auto
string(const char (&array)[Size]) -> /* Some metafunction using `array` */
Como antes, encontramos o problema de que a matriz, agora um parâmetro para a constexpr
função, não é mais um constexpr
tipo.
Eu acredito que deve ser possível definir uma macro do pré-processador C que usa uma string e o tamanho da string como argumentos e retorna uma sequência que consiste nos caracteres da string (using BOOST_PP_FOR
, stringification, subscritos de matriz e similares). No entanto, não tenho tempo (ou interesse suficiente) para implementar essa macro =)
constexpr
funções e inicializar matrizes (portanto, concat, substr etc.).
constexpr
seqüências de caracteres podem ser analisadas durante o tempo de compilação, para que você possa seguir caminhos de código diferentes, dependendo dos resultados. Essencialmente, você pode criar EDLs no C ++; as aplicações são bastante ilimitadas.