Wygodne deklarowanie ciągów kompilacyjnych w C ++
Możliwość tworzenia i manipulowania ciągami znaków podczas kompilacji w C ++ ma kilka przydatnych aplikacji. Chociaż możliwe jest tworzenie ciągów kompilacyjnych w C ++, proces jest bardzo uciążliwy, ponieważ ciąg musi być zadeklarowany jako zmienna sekwencja znaków, np.
using str = sequence<'H', 'e', 'l', 'l', 'o', ', ', 'w', 'o', 'r', 'l', 'd', '!'>;
Operacje takie jak konkatenacja łańcuchów, wyodrębnianie podłańcuchowe i wiele innych można łatwo zaimplementować jako operacje na sekwencjach znaków.Czy można wygodniej deklarować ciągi czasu kompilacji? Jeśli nie, czy w pracach znajduje się propozycja, która pozwoliłaby na wygodne zadeklarowanie ciągów kompilacyjnych?
Dlaczego istniejące podejścia nie powiodły sięNajlepiej byłoby, gdybyśmy mogli deklarować ciągi czasu kompilacji w następujący sposób:
// Approach 1
using str1 = sequence<"Hello, world!">;
lub, używając literałów zdefiniowanych przez użytkownika,
// Approach 2
constexpr auto str2 = "Hello, world!"_s;
gdziedecltype(str2)
miałbyconstexpr
konstruktor. Możliwa jest bardziej chaotyczna wersja podejścia 1, wykorzystująca fakt, że można wykonać następujące czynności:
template <unsigned Size, const char Array[Size]>
struct foo;
Jednak tablica musiałaby mieć powiązanie zewnętrzne, więc aby podejście 1 zadziałało, musielibyśmy napisać coś takiego:
/* Implementation of array to sequence goes here. */
constexpr const char str[] = "Hello, world!";
int main()
{
using s = string<13, str>;
return 0;
}
Nie trzeba dodawać, że jest to bardzo niewygodne. Podejście 2 nie jest możliwe do zrealizowania. Gdybyśmy zadeklarowali (constexpr
) operator literału, w jaki sposób określilibyśmy typ powrotu? Ponieważ potrzebujemy operatora, aby zwrócił zmienną sekwencję znaków, więc musielibyśmy użyćconst char*
parametr określający typ powrotu:
constexpr auto
operator"" _s(const char* s, size_t n) -> /* Some metafunction using `s` */
Powoduje to błąd kompilacji, ponieważs
nie jestconstexpr
. Próba obejścia tego problemu w następujący sposób niewiele pomaga.
template <char... Ts>
constexpr sequence<Ts...> operator"" _s() { return {}; }
Standard nakazuje, aby ta konkretna literalna forma operatora była zarezerwowana dla typów całkowitych i zmiennoprzecinkowych. Podczas123_s
pracowałbym,abc_s
nie. Co, jeśli całkowicie wykopiemy literały zdefiniowane przez użytkownika i po prostu użyjemy zwykłegoconstexpr
funkcjonować?
template <unsigned Size>
constexpr auto
string(const char (&array)[Size]) -> /* Some metafunction using `array` */
Tak jak poprzednio, natrafiamy na problem, że tablica, teraz parametr doconstexpr
funkcja, sama w sobie nie jest jużconstexpr
rodzaj.
Uważam, że powinno być możliwe zdefiniowanie makra preprocesora C, które pobiera ciąg znaków i rozmiar ciągu jako argumenty i zwraca sekwencję składającą się ze znaków w łańcuchu (przy użyciuBOOST_PP_FOR
, naciąganie, indeksy macierzy i tym podobne). Jednak nie mam czasu (lub wystarczającego zainteresowania) na wdrożenie takiego makro =)