Être capable de créer et de manipuler des chaînes pendant la compilation en C ++ a plusieurs applications utiles. Bien qu'il soit possible de créer des chaînes de compilation en C ++, le processus est très lourd, car la chaîne doit être déclarée comme une séquence variadique de caractères, par exemple
using str = sequence<'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'>;
Des opérations telles que la concaténation de chaînes, l'extraction de sous-chaînes et bien d'autres peuvent facilement être implémentées en tant qu'opérations sur des séquences de caractères. Est-il possible de déclarer des chaînes de compilation plus facilement? Sinon, y a-t-il une proposition dans les travaux qui permettrait une déclaration pratique des chaînes de compilation?
Pourquoi les approches existantes échouent
Idéalement, nous aimerions pouvoir déclarer des chaînes de compilation comme suit:
// Approach 1
using str1 = sequence<"Hello, world!">;
ou, en utilisant des littéraux définis par l'utilisateur,
// Approach 2
constexpr auto str2 = "Hello, world!"_s;
où decltype(str2)
aurait un constexpr
constructeur. Une version plus désordonnée de l'approche 1 est possible à mettre en œuvre, en tirant parti du fait que vous pouvez effectuer les opérations suivantes:
template <unsigned Size, const char Array[Size]>
struct foo;
Cependant, le tableau devrait avoir un lien externe, donc pour que l'approche 1 fonctionne, nous devions écrire quelque chose comme ceci:
/* Implementation of array to sequence goes here. */
constexpr const char str[] = "Hello, world!";
int main()
{
using s = string<13, str>;
return 0;
}
Inutile de dire que c'est très gênant. L'approche 2 n'est en fait pas possible à mettre en œuvre. Si nous devions déclarer un constexpr
opérateur littéral ( ), comment spécifierions-nous le type de retour? Puisque nous avons besoin de l'opérateur pour renvoyer une séquence variadique de caractères, nous aurions donc besoin d'utiliser le const char*
paramètre pour spécifier le type de retour:
constexpr auto
operator"" _s(const char* s, size_t n) -> /* Some metafunction using `s` */
Cela entraîne une erreur de compilation, car ce s
n'est pas un fichier constexpr
. Essayer de contourner ce problème en procédant comme suit n'aide pas beaucoup.
template <char... Ts>
constexpr sequence<Ts...> operator"" _s() { return {}; }
La norme stipule que cette forme d'opérateur littéral spécifique est réservée aux types entiers et flottants. Cela 123_s
fonctionnerait, mais abc_s
pas. Et si nous abandonnions complètement les littéraux définis par l'utilisateur et utilisions simplement une constexpr
fonction régulière ?
template <unsigned Size>
constexpr auto
string(const char (&array)[Size]) -> /* Some metafunction using `array` */
Comme auparavant, nous nous heurtons au problème que le tableau, maintenant un paramètre de la constexpr
fonction, n'est plus un constexpr
type.
Je pense qu'il devrait être possible de définir une macro de préprocesseur C qui prend une chaîne et la taille de la chaîne comme arguments, et renvoie une séquence composée des caractères de la chaîne (utilisation BOOST_PP_FOR
, stringification, indices de tableau, etc.). Cependant, je n'ai pas le temps (ou assez d'intérêt) pour implémenter une telle macro =)
constexpr
fonctions et initialiser des tableaux (par conséquent, concat, substr, etc.).
constexpr
chaînes peuvent être analysées pendant la compilation, de sorte que vous pouvez prendre différents chemins de code en fonction des résultats. Essentiellement, vous pouvez créer des EDL dans C ++; les applications sont assez illimitées.