Benutzerdefinierte Literale (seit C++11)
Ermöglicht es ganzzahligen, Gleitkomma-, Zeichen- und Zeichenkettenliteralen, Objekte eines benutzerdefinierten Typs zu erzeugen, indem ein benutzerdefiniertes Suffix definiert wird.
Inhalt |
[bearbeiten] Syntax
Ein benutzerdefiniertes Literal ist ein Ausdruck einer der folgenden Formen
| Dezimalliteral ud-suffix | (1) | ||||||||
| Oktalliteral ud-suffix | (2) | ||||||||
| Hexadezimalliteral ud-suffix | (3) | ||||||||
| Binärliteral ud-suffix | (4) | ||||||||
| fraktionales-literal exponent-teil (optional) ud-suffix | (5) | ||||||||
| ziffernfolge exponent-teil ud-suffix | (6) | ||||||||
| Zeichenliteral ud-suffix | (7) | ||||||||
| Zeichenkettenliteral ud-suffix | (8) | ||||||||
| Dezimalliteral | - | wie in Ganzzahlliteral, eine nicht-null Dezimalziffer gefolgt von null oder mehr Dezimalziffern |
| Oktalliteral | - | wie in Ganzzahlliteral, eine Null gefolgt von null oder mehr Oktalziffern |
| Hexadezimalliteral | - | wie in Ganzzahlliteral, 0x oder 0X gefolgt von einer oder mehreren Hexadezimalziffern |
| Binärliteral | - | wie in Ganzzahlliteral, 0b oder 0B gefolgt von einer oder mehreren Binärziffern |
| Ziffernfolge | - | wie in Gleitkommaliteral, eine Folge von Dezimalziffern |
| Fraktionales-literal | - | wie in Gleitkommaliteral, entweder eine ziffernfolge gefolgt von einem Punkt (123.) oder eine optionale ziffernfolge gefolgt von einem Punkt und einer weiteren ziffernfolge (1.0 oder .12) |
| Exponent-teil | - | wie in Gleitkommaliteral, der Buchstabe e oder der Buchstabe E gefolgt von einem optionalen Vorzeichen und einer ziffernfolge |
| Zeichenliteral | - | wie in Zeichenliteral |
| string-literal | - | wie in Zeichenkettenliteral, einschließlich roher Zeichenkettenliterale |
| ud-suffix | - | ein Bezeichner, eingeführt durch einen Literaloperator oder eine Literaloperator-Vorlage (siehe unten) |
|
In den Ganzzahl- und Gleitkomma- Ziffernfolgen sind optionale Trennzeichen |
(seit C++14) |
Wenn ein Token mit einer benutzerdefinierten Literalsyntax und einer regulären Literalsyntax übereinstimmt, wird es als reguläres Literal angenommen (d. h., es ist unmöglich, LL in 123LL zu überladen).
Wenn der Compiler ein benutzerdefiniertes Literal mit ud-suffix X antrifft, führt er eine qualifizierte Namenssuche durch und sucht nach einer Funktion mit dem Namen operator""X. Wenn die Suche keine Deklaration findet, ist das Programm schlecht geformt. Andernfalls:
|
a) Wenn die Überladungsmenge eine Zeichenkettenliteral-Operator-Vorlage mit einem Nicht-Typ-Template-Parameter enthält, für den str ein wohlgeformtes Template-Argument ist, dann wird der benutzerdefinierte Literalausdruck als Funktionsaufruf behandelt: operator ""X<str>(); |
(seit 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; // calls operator ""_w(1.2L) u"one"_w; // calls operator ""_w(u"one", 3) 12_w; // calls operator ""_w("12") "two"_w; // error: no applicable literal operator }
Wenn Zeichenkettenliterale in Übersetzungsphase 6 verkettet werden, werden auch benutzerdefinierte Zeichenkettenliterale verkettet, und ihre ud-suffixe werden für die Verkettung ignoriert, mit der Ausnahme, dass nur ein Suffix bei allen verketteten Literalen erscheinen darf.
int main() { L"A" "B" "C"_x; // OK: same as L"ABC"_x "P"_x "Q" "R"_y; // error: two different ud-suffixes (_x and _y) }
[bearbeiten] Literaloperatoren
Die Funktion, die von einem benutzerdefinierten Literal aufgerufen wird, ist als Literaloperator (oder, wenn es eine Vorlage ist, Literaloperator-Vorlage) bekannt. Sie wird wie jede andere Funktion oder Funktionsvorlage im Namespace-Gültigkeitsbereich deklariert (sie kann auch eine Freundschaftsfunktion, eine explizite Instanziierung oder Spezialisierung einer Funktionsvorlage sein oder durch eine using-Deklaration eingeführt werden), mit den folgenden Einschränkungen:
Der Name dieser Funktion kann eine der beiden Formen haben:
operator "" bezeichner |
(1) | (veraltet) | |||||||
operator benutzerdefiniertes-zeichenkettenliteral |
(2) | ||||||||
| identifier | - | der bezeichner, der als ud-suffix für die benutzerdefinierten Literale verwendet wird, die diese Funktion aufrufen werden |
| benutzerdefiniertes-zeichenkettenliteral | - | die Zeichenfolge "" gefolgt, ohne Leerzeichen, von der Zeichenfolge, die zum ud-suffix wird |
ud-suffix muss mit dem Unterstrich _ beginnen: Suffixe, die nicht mit einem Unterstrich beginnen, sind für die von der Standardbibliothek bereitgestellten Literaloperatoren reserviert. Er darf auch keine doppelten Unterstriche __ enthalten: solche Suffixe sind ebenfalls reserviert.
Wenn der Literaloperator eine Vorlage ist, muss er eine leere Parameterliste haben und darf nur einen Template-Parameter haben, der eine Nicht-Typ-Template-Parameterliste mit dem Elementtyp char sein muss (in diesem Fall als numerischer Literaloperator-Vorlage bezeichnet)
template<char...> double operator ""_x();
|
oder ein Nicht-Typ-Template-Parameter vom Klassentyp (in diesem Fall als Zeichenkettenliteraloperator-Vorlage bezeichnet) struct A { constexpr A(const char*); }; template<A a> A operator ""_a(); |
(seit C++20) |
Nur die folgenden Parameterlisten sind für Literaloperatoren zulässig:
( const char* ) |
(1) | ||||||||
( unsigned long long int ) |
(2) | ||||||||
( long double ) |
(3) | ||||||||
( char ) |
(4) | ||||||||
( wchar_t ) |
(5) | ||||||||
( char8_t ) |
(6) | (seit 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) | (seit C++20) | |||||||
( const char16_t*, std::size_t ) |
(12) | ||||||||
( const char32_t*, std::size_t ) |
(13) | ||||||||
Standardargumente sind nicht erlaubt.
C-Sprachbindung ist nicht erlaubt.
Abgesehen von den oben genannten Einschränkungen sind Literaloperatoren und Literaloperator-Vorlagen normale Funktionen (und Funktionsvorlagen), sie können inline oder constexpr deklariert werden, sie können interne oder externe Bindung haben, sie können explizit aufgerufen werden, ihre Adressen können genommen werden usw.
#include <string> void operator ""_km(long double); // OK, will be called for 1.0_km void operator "" _km(long double); // same as above, deprecated std::string operator ""_i18n(const char*, std::size_t); // OK template<char...> double operator ""_pi(); // OK float operator ""_e(const char*); // OK // error: suffix must begin with underscore float operator ""Z(const char*); // error: all names that begin with underscore followed by uppercase // letter are reserved (NOTE: a space between "" and _). double operator"" _Z(long double); // OK. NOTE: no space between "" and _. double operator""_Z(long double); // OK: literal operators can be overloaded double operator ""_Z(const char* args); int main() {}
[bearbeiten] Anmerkungen
Seit der Einführung von benutzerdefinierten Literalen ist der Code, der Format-Makrokonstanten für ganzzahlige Typen fester Breite ohne Leerzeichen nach dem vorhergehenden Zeichenkettenliteral verwendet, ungültig geworden: std::printf("%"PRId64"\n",INT64_MIN); muss ersetzt werden durch std::printf("%" PRId64"\n",INT64_MIN);.
Aufgrund des maximalen Munch müssen benutzerdefinierte Ganzzahl- und Gleitkommaliterale, die auf p, P,(seit C++17) e und E enden und von den Operatoren + oder - gefolgt werden, durch ein Leerzeichen oder Klammern im Quellcode von dem Operator getrennt werden.
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; // error 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; // error auto u = 1_p +2; // OK
Dasselbe gilt für den Punktoperator, der auf ein ganzzahliges oder Gleitkomma-Benutzerdefiniertes Literal folgt.
#include <chrono> using namespace std::literals; auto a = 4s.count(); // Error auto b = 4s .count(); // OK auto c = (4s).count(); // OK
Andernfalls wird ein einzelnes ungültiges Präprozessor-Zahlentoken (z. B. 1.0_E+2.0 oder 4s.count) gebildet, was zu einem Kompilierungsfehler führt.
| Feature-Testmakro | Wert | Std | Feature |
|---|---|---|---|
__cpp_user_defined_literals |
200809L |
(C++11) | Benutzerdefinierte Literale |
[bearbeiten] Schlüsselwörter
[bearbeiten] Beispiele
#include <algorithm> #include <cstddef> #include <iostream> #include <numbers> #include <string> // used as conversion from degrees (input param) to radians (returned output) constexpr long double operator""_deg_to_rad(long double deg) { long double radians = deg * std::numbers::pi_v<long double> / 180; return radians; } // used with custom type struct mytype { unsigned long long m; }; constexpr mytype operator""_mytype(unsigned long long n) { return mytype{n}; } // used for side-effects 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'; }
Ausgabe
1.570796 123 0x123ABC abcabc
[bearbeiten] Standardbibliothek
Die folgenden Literaloperatoren sind in der Standardbibliothek definiert:
| Definiert im Inline-Namespace
std::literals::complex_literals | |
| ein std::complex Literal, das eine rein imaginäre Zahl darstellt. (function) | |
| Definiert im Inline-Namespace
std::literals::chrono_literals | |
| (C++14) |
ein std::chrono::duration Literal, das Stunden repräsentiert (Funktion) |
| (C++14) |
ein std::chrono::duration Literal, das Minuten repräsentiert (Funktion) |
| (C++14) |
ein std::chrono::duration Literal, das Sekunden repräsentiert (Funktion) |
| (C++14) |
ein std::chrono::duration Literal, das Millisekunden repräsentiert (Funktion) |
| (C++14) |
ein std::chrono::duration Literal, das Mikrosekunden repräsentiert (Funktion) |
| (C++14) |
ein std::chrono::duration Literal, das Nanosekunden repräsentiert (Funktion) |
| (C++20) |
ein std::chrono::year Literal, das ein bestimmtes Jahr repräsentiert (Funktion) |
| (C++20) |
ein std::chrono::day Literal, das einen Tag eines Monats repräsentiert (Funktion) |
| Definiert im Inline-Namespace
std::literals::string_literals | |
| (C++14) |
konvertiert ein Zeichenkettenliteral in basic_string(function) |
| Definiert im Inline-Namespace
std::literals::string_view_literals | |
| (C++17) |
erzeugt eine Zeichenansicht eines Zeichenkettenliteral (Funktion) |
[bearbeiten] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 1473 | C++11 | Leerzeichen zwischen "" und ud-suffix war erforderlich in der Deklaration von Literaloperatoren. |
optional gemacht. |
| CWG 1479 | C++11 | Literaloperatoren konnten Standardargumente haben. | verboten |
| CWG 2521 | C++11 | operator"" _Bq war schlecht geformt (keine Diagnose erforderlich), da er den reservierten Bezeichner _Bq verwendet. |
veraltete die Literaloperator-Syntax mit Leerzeichen zwischen "" und ud-suffix. |