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 =)

questionAnswers(13)

yourAnswerToTheQuestion