Pages

samedi 15 décembre 2012

Les littéraux

En C++11 le langage introduit les littéraux définis par l'utilisateur. Pour rappel, les littéraux permettent de forcer un type via un suffixe, comme avec 1L pour créer un long.

Les littéraux se définissent par un nouvel opérateur: operator "", et le nom du suffixe (identifiant) doit obligatoirement être précédé d'un underscore. Les suffixes sans underscrore sont réservés par les standards existants ou à venir.
À noter qu'un espace -ou saut de ligne- est obligatoire après "".

Il existe deux types de littéraux, ceux sur des nombres et ceux sur des caractères.

Littéraux sur nombres

result_type operator "" _suffix(unsigned long long); // 334_suffix
result_type operator "" _suffix(double long); // 334.2_suffix
template<char...> result_type operator "" _suffix(); // 334_suffix ou  334.2_suffix
result_type operator "" _s(const char *); // 334_suffix ou  334.2_suffix

Quatre prototypes, le premier s'utilise sur des entiers, le second sur des nombres flottants, les troisième et quatrième pour entiers ou flottants et sont cachés par les 2 premiers si définis.

L'overflow

Le problème est que le paramètre peut être plus grand que le contenu du type de retour.
Par exemple, si _suffix retourne un short alors 99999_suffix doit générer une erreur de compilation car la valeur est trop grande.
En utilisant les 2 premiers prototypes, cette vérification ne peut pas se faire, le paramètre d'une fonction n'étant pas considéré comme const-expressif, static_cast ne peut pas être utilisé dessus et donc: pas de vérification à la compilation.
Le troisième prototype est le seul moyen de gérer l'overflow. Cependant son utilisation peut devenir complexe…
J'intégrerai bientôt dans falcon/literal une classe pour simplifier cette vérification ;).

Littéraux sur caractères

result_type operator "" _suffix(char); // '2'_suffix
result_type operator "" _suffix(const char *, std::size_t len); // "334"_suffix

Un prototype pour les caractères et un autre pour les chaînes. Ce dernier prend la taille de la chaîne en second paramètre.
À noter que char peut être remplacé par wchar_t, char16_t ou char32_t, ce qui fait un total de 8 prototypes.

Un cas d'utilisation simple est la concaténation de chaîne std::string("text: ") + str qui peut être simplifier en "text: "_s + str

std::string operator "" _s(const char * s, std::size_t len)
{ return std::string(s, len); }

Pour finir

Je vous propose d'aller jeter un œil ou deux dans falcon/literal (sans vouloir insister :o)).
En cadeau la liste des littéraux prédéfinis dans le standard:

Aucun commentaire: