Essere in grado di creare e manipolare stringhe durante la compilazione in C ++ ha diverse utili applicazioni. Sebbene sia possibile creare stringhe in fase di compilazione in C ++, il processo è molto complicato, poiché la stringa deve essere dichiarata come una sequenza variadica di caratteri, ad es.
using str = sequence<'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'>;
Operazioni come la concatenazione di stringhe, l'estrazione di sottostringhe e molte altre, possono essere facilmente implementate come operazioni su sequenze di caratteri. È possibile dichiarare le stringhe in fase di compilazione in modo più conveniente? In caso contrario, esiste una proposta in corso che consenta una comoda dichiarazione delle stringhe in fase di compilazione?
Perché gli approcci esistenti falliscono
Idealmente, vorremmo essere in grado di dichiarare le stringhe in fase di compilazione come segue:
// Approach 1
using str1 = sequence<"Hello, world!">;
oppure, usando valori letterali definiti dall'utente,
// Approach 2
constexpr auto str2 = "Hello, world!"_s;
dove decltype(str2)
avrebbe un constexpr
costruttore. È possibile implementare una versione più disordinata dell'approccio 1, sfruttando il fatto che è possibile effettuare le seguenti operazioni:
template <unsigned Size, const char Array[Size]>
struct foo;
Tuttavia, l'array dovrebbe avere un collegamento esterno, quindi per far funzionare l'approccio 1, dovremmo scrivere qualcosa del genere:
/* Implementation of array to sequence goes here. */
constexpr const char str[] = "Hello, world!";
int main()
{
using s = string<13, str>;
return 0;
}
Inutile dire che questo è molto scomodo. L'approccio 2 in realtà non è possibile implementare. Se dovessimo dichiarare un ( constexpr
) letterale operatore, come potremmo specificare il tipo restituito? Poiché è necessario che l'operatore restituisca una sequenza variadica di caratteri, è necessario utilizzare il const char*
parametro per specificare il tipo restituito:
constexpr auto
operator"" _s(const char* s, size_t n) -> /* Some metafunction using `s` */
Ciò provoca un errore di compilazione, perché s
non è un constexpr
. Cercare di aggirare il problema nel modo seguente non aiuta molto.
template <char... Ts>
constexpr sequence<Ts...> operator"" _s() { return {}; }
Lo standard impone che questo specifico modulo di operatore letterale sia riservato ai tipi interi e in virgola mobile. Mentre 123_s
funzionerebbe, abc_s
no. Cosa succede se abbandoniamo del tutto i letterali definiti dall'utente e utilizziamo semplicemente una constexpr
funzione regolare ?
template <unsigned Size>
constexpr auto
string(const char (&array)[Size]) -> /* Some metafunction using `array` */
Come prima, incontriamo il problema che l'array, ora un parametro della constexpr
funzione, non è più un constexpr
tipo.
Credo che dovrebbe essere possibile definire una macro del preprocessore C che accetta una stringa e la dimensione della stringa come argomenti e restituisce una sequenza composta dai caratteri nella stringa (utilizzo BOOST_PP_FOR
, stringa, sottoscrizioni di array e simili). Tuttavia, non ho il tempo (o abbastanza interesse) per implementare tale macro =)
constexpr
funzioni e inizializzare matrici (quindi, concat, substr ecc.).
constexpr
stringhe possono essere analizzate durante il tempo di compilazione, in modo da poter prendere diversi percorsi di codice a seconda dei risultati. In sostanza, è possibile creare EDL in C ++; le applicazioni sono piuttosto illimitate.