User-defined literals (since C++11)
Permet aux littéraux entiers, à virgule flottante, caractères et chaînes de produire des objets de type défini par l'utilisateur en définissant un suffixe défini par l'utilisateur.
Table des matières |
Syntaxe
Un littéral défini par l'utilisateur est une expression de l'une des formes suivantes
| decimal-literal ud-suffix | (1) | ||||||||
| octal-literal ud-suffix | (2) | ||||||||
| hex-literal ud-suffix | (3) | ||||||||
| binary-literal ud-suffix | (4) | ||||||||
| fractional-constant exponent-part (optionnel) ud-suffix | (5) | ||||||||
| digit-sequence exponent-part ud-suffix | (6) | ||||||||
| character-literal ud-suffix | (7) | ||||||||
| string-literal ud-suffix | (8) | ||||||||
| decimal-literal | - | identique au littéral entier , un chiffre décimal non nul suivi de zéro ou plusieurs chiffres décimaux |
| octal-literal | - | identique au littéral entier , un zéro suivi de zéro ou plusieurs chiffres octaux |
| hex-literal | - |
identique au
littéral entier
,
0x
ou
0X
suivi d'un ou plusieurs chiffres hexadécimaux
|
| binary-literal | - |
identique au
littéral entier
,
0b
ou
0B
suivi d'un ou plusieurs chiffres binaires
|
| digit-sequence | - | identique au littéral flottant , une séquence de chiffres décimaux |
| fractional-constant | - | identique au littéral flottant , soit une digit-sequence suivie d'un point ( 123 . ) ou une digit-sequence optionnelle suivie d'un point et d'une autre digit-sequence ( 1.0 ou .12 ) |
| exponent-part | - |
identique au
littéral flottant
, la lettre
e
ou la lettre
E
suivie d'un signe optionnel, suivi d'une
digit-sequence
|
| character-literal | - | identique au littéral de caractère |
| string-literal | - | identique au littéral de chaîne , incluant les littéraux de chaîne bruts |
| ud-suffix | - | un identificateur, introduit par une déclaration d' opérateur littéral ou de modèle d'opérateur littéral (voir ci-dessous ) |
|
Dans les séquences de chiffres des
littéraux entiers
et
flottants
, les séparateurs optionnels
|
(depuis C++14) |
Si un jeton correspond à la syntaxe d'un littéral défini par l'utilisateur et à une syntaxe de littéral régulier, il est considéré comme un littéral régulier (c'est-à-dire qu'il est impossible de surcharger
LL
dans
123LL
).
Lorsque le compilateur rencontre un littéral défini par l'utilisateur avec le
ud-suffix
X
, il effectue une
recherche de nom non qualifié
, cherchant une fonction avec le nom
operator
""
X
. Si la recherche ne trouve pas de déclaration, le programme est mal formé. Sinon,
|
a)
Si l'ensemble de surcharge inclut un modèle d'opérateur de littéral de chaîne avec un paramètre de modèle constant pour lequel
str
est un argument de modèle valide, alors l'expression littérale définie par l'utilisateur est traitée comme un appel de fonction
operator
""
X
<
str
>
(
)
;
|
(depuis C++20) |
long double operator ""_w(long double); std::string operator ""_w(const char16_t*, size_t); unsigned operator ""_w(const char*); int main() { 1.2_w; // appelle operator ""_w(1.2L) u"one"_w; // appelle operator ""_w(u"one", 3) 12_w; // appelle operator ""_w("12") "two"_w; // erreur : aucun opérateur littéral applicable }
Lorsque la concaténation de littéraux de chaîne a lieu dans la phase de traduction 6 , les littéraux de chaîne définis par l'utilisateur sont également concaténés, et leurs ud-suffix sont ignorés pour la concaténation, sauf qu'un seul suffixe peut apparaître sur tous les littéraux concaténés :
int main() { L"A" "B" "C"_x; // OK : identique à L"ABC"_x "P"_x "Q" "R"_y; // erreur : deux suffixes utilisateur différents (_x et _y) }
Opérateurs littéraux
La fonction appelée par un littéral défini par l'utilisateur est appelée opérateur littéral (ou, s'il s'agit d'un template, opérateur littéral template ). Elle est déclarée comme toute autre fonction ou fonction template au niveau de l'espace de noms (elle peut également être une fonction amie, une instanciation explicite ou une spécialisation d'un template de fonction, ou être introduite par une using-declaration), à l'exception des restrictions suivantes :
Le nom de cette fonction peut avoir l'une des deux formes :
operator ""
identifiant
|
(1) | (obsolète) | |||||||
operator
littéral-chaîne-défini-par-utilisateur
|
(2) | ||||||||
| identifier | - | l' identifiant à utiliser comme suffixe-ud pour les littéraux définis par l'utilisateur qui appelleront cette fonction |
| user-defined-string-literal | - |
la séquence de caractères
""
suivie, sans espace, par la séquence de caractères qui devient le
suffixe-ud
|
ud-suffix
doit commencer par le soulignement
_
: les suffixes qui ne commencent pas par le soulignement sont réservés pour les opérateurs littéraux fournis par la bibliothèque standard. Il ne peut pas contenir de doubles soulignements
__
non plus : de tels suffixes sont également réservés.
Si l'opérateur littéral est un modèle, il doit avoir une liste de paramètres vide et ne peut avoir qu'un seul paramètre de modèle, qui doit être un pack de paramètres de modèle constant avec le type d'élément char (auquel cas il est connu comme un opérateur littéral numérique modèle ):
template<char...> double operator ""_x();
|
ou un paramètre de modèle constant de type classe (auquel cas il est connu sous le nom d' opérateur de modèle de littéral de chaîne ) : struct A { constexpr A(const char*); }; template<A a> A operator ""_a(); |
(depuis C++20) |
Seules les listes de paramètres suivantes sont autorisées pour les opérateurs littéraux :
(
const
char
*
)
|
(1) | ||||||||
(
unsigned
long
long
int
)
|
(2) | ||||||||
(
long
double
)
|
(3) | ||||||||
(
char
)
|
(4) | ||||||||
(
wchar_t
)
|
(5) | ||||||||
(
char8_t
)
|
(6) | (depuis C++20) | |||||||
(
char16_t
)
|
(7) | ||||||||
(
char32_t
)
|
(8) | ||||||||
(
const
char
*
,
std::size_t
)
|
(9) | ||||||||
(
const
wchar_t
*
,
std::size_t
)
|
(10) | ||||||||
(
const
char8_t
*
,
std::size_t
)
|
(11) | (depuis C++20) | |||||||
(
const
char16_t
*
,
std::size_t
)
|
(12) | ||||||||
(
const
char32_t
*
,
std::size_t
)
|
(13) | ||||||||
Les arguments par défaut ne sont pas autorisés.
La linkage de langage C n'est pas autorisée.
En dehors des restrictions ci-dessus, les opérateurs littéraux et les modèles d'opérateurs littéraux sont des fonctions normales (et des modèles de fonctions), ils peuvent être déclarés inline ou constexpr, ils peuvent avoir une liaison interne ou externe, ils peuvent être appelés explicitement, leurs adresses peuvent être prises, etc.
#include <string> void operator ""_km(long double); // OK, sera appelé pour 1.0_km void operator "" _km(long double); // identique au précédent, déprécié std::string operator ""_i18n(const char*, std::size_t); // OK template<char...> double operator ""_pi(); // OK float operator ""_e(const char*); // OK // erreur : le suffixe doit commencer par un tiret bas float operator ""Z(const char*); // erreur : tous les noms commençant par un tiret bas suivi d'une lettre majuscule // sont réservés (NOTE : un espace entre "" et _). double operator"" _Z(long double); // OK. NOTE : pas d'espace entre "" et _. double operator""_Z(long double); // OK : les opérateurs littéraux peuvent être surchargés double operator ""_Z(const char* args); int main() {}
Notes
Depuis l'introduction des littéraux définis par l'utilisateur, le code qui utilise les constantes de macro de format pour les types entiers de largeur fixe sans espace après le littéral de chaîne précédent est devenu invalide : std:: printf ( "%" PRId64 " \n " , INT64_MIN ) ; doit être remplacé par std:: printf ( "%" PRId64 " \n " , INT64_MIN ) ; .
En raison du
maximal munch
, les littéraux entiers et flottants définis par l'utilisateur se terminant par
p
,
P
,
(depuis C++17)
e
et
E
, lorsqu'ils sont suivis des opérateurs
+
ou
-
, doivent être séparés de l'opérateur par un espace ou des parenthèses dans le code source :
long double operator""_E(long double); long double operator""_a(long double); int operator""_p(unsigned long long); auto x = 1.0_E+2.0; // erreur auto y = 1.0_a+2.0; // OK auto z = 1.0_E +2.0; // OK auto q = (1.0_E)+2.0; // OK auto w = 1_p+2; // erreur auto u = 1_p +2; // OK
Il en va de même pour l'opérateur point suivant un littéral défini par l'utilisateur de type entier ou flottant :
#include <chrono> using namespace std::literals; auto a = 4s.count(); // Erreur auto b = 4s .count(); // OK auto c = (4s).count(); // OK
Sinon, un seul jeton de prétraitement numérique invalide (par exemple, 1.0 _E + 2.0 ou 4s. count ) est formé, ce qui entraîne l'échec de la compilation.
| Macro de test de fonctionnalité | Valeur | Std | Fonctionnalité |
|---|---|---|---|
__cpp_user_defined_literals
|
200809L
|
(C++11) | Littéraux définis par l'utilisateur |
Mots-clés
Exemples
#include <algorithm> #include <cstddef> #include <iostream> #include <numbers> #include <string> // utilisé comme conversion de degrés (paramètre d'entrée) en radians (sortie retournée) constexpr long double operator""_deg_to_rad(long double deg) { long double radians = deg * std::numbers::pi_v<long double> / 180; return radians; } // utilisé avec un type personnalisé struct mytype { unsigned long long m; }; constexpr mytype operator""_mytype(unsigned long long n) { return mytype{n}; } // utilisé pour les effets de bord void operator""_print(const char* str) { std::cout << str << '\n'; } #if __cpp_nontype_template_args < 201911 std::string operator""_x2 (const char* str, std::size_t) { return std::string{str} + str; } #else // C++20 string literal operator template template<std::size_t N> struct DoubleString { char p[N + N - 1]{}; constexpr DoubleString(char const(&pp)[N]) { std::ranges::copy(pp, p); std::ranges::copy(pp, p + N - 1); } }; template<DoubleString A> constexpr auto operator""_x2() { return A.p; } #endif // C++20 int main() { double x_rad = 90.0_deg_to_rad; std::cout << std::fixed << x_rad << '\n'; mytype y = 123_mytype; std::cout << y.m << '\n'; 0x123ABC_print; std::cout << "abc"_x2 << '\n'; }
Sortie :
1.570796 123 0x123ABC abcabc
Bibliothèque standard
Les opérateurs littéraux suivants sont définis dans la bibliothèque standard :
|
Défini dans l'espace de noms en ligne
std::literals::complex_literals
|
|
|
un littéral
std::complex
représentant un nombre purement imaginaire
(fonction) |
|
|
Défini dans l'espace de noms en ligne
std::literals::chrono_literals
|
|
|
(C++14)
|
un littéral
std::chrono::duration
représentant des heures
(fonction) |
|
(C++14)
|
un littéral
std::chrono::duration
représentant des minutes
(fonction) |
|
(C++14)
|
un littéral
std::chrono::duration
représentant des secondes
(fonction) |
|
(C++14)
|
un littéral
std::chrono::duration
représentant des millisecondes
(fonction) |
|
(C++14)
|
un littéral
std::chrono::duration
représentant des microsecondes
(fonction) |
|
(C++14)
|
un littéral
std::chrono::duration
représentant des nanosecondes
(fonction) |
|
(C++20)
|
un littéral
std::chrono::year
représentant une année particulière
(fonction) |
|
(C++20)
|
un littéral
std::chrono::day
représentant un jour du mois
(fonction) |
|
Défini dans l'espace de noms en ligne
std::literals::string_literals
|
|
|
(C++14)
|
convertit un littéral de tableau de caractères en
basic_string
(fonction) |
|
Défini dans l'espace de noms en ligne
std::literals::string_view_literals
|
|
|
(C++17)
|
crée une vue de chaîne d'un littéral de tableau de caractères
(fonction) |
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement publié | Comportement correct |
|---|---|---|---|
| CWG 1473 | C++11 |
l'espace blanc entre
""
et
ud-suffix
était
requis dans la déclaration des opérateurs littéraux |
rendu optionnel |
| CWG 1479 | C++11 | les opérateurs littéraux pouvaient avoir des arguments par défaut | interdit |
| CWG 2521 | C++11 |
operator
""
_Bq
était mal formé (aucun diagnostic
requis) car il utilise l'identifiant réservé
_Bq
|
a déprécié la syntaxe d'opérateur littéral
avec espace blanc entre "" et ud-suffix |