ユーザー定義リテラル (C++11以降)
整数、浮動小数点、文字、および文字列リテラルにユーザー定義の接尾辞を定義することで、ユーザー定義型のオブジェクトを生成できるようにします。
目次 |
[編集] 構文
ユーザー定義リテラルは、以下のいずれかの形式の式です。
| decimal-literal ud-suffix | (1) | ||||||||
| octal-literal ud-suffix | (2) | ||||||||
| hex-literal ud-suffix | (3) | ||||||||
| binary-literal ud-suffix | (4) | ||||||||
| fractional-constant exponent-part (オプション) ud-suffix | (5) | ||||||||
| digit-sequence exponent-part ud-suffix | (6) | ||||||||
| character-literal ud-suffix | (7) | ||||||||
| string-literal ud-suffix | (8) | ||||||||
| decimal-literal | - | 整数リテラルと同じで、0以外の10進数字の後に0個以上の10進数字が続く |
| octal-literal | - | 整数リテラルと同じで、0の後に0個以上の8進数字が続く |
| hex-literal | - | 整数リテラルと同じで、0x または 0X の後に1個以上の16進数字が続く |
| binary-literal | - | 整数リテラルと同じで、0b または 0B の後に1個以上の2進数字が続く |
| digit-sequence | - | 浮動小数点リテラルと同じで、10進数字のシーケンス |
| fractional-constant | - | 浮動小数点リテラルと同じで、digit-sequence の後にドット (123.) が続くか、またはオプションの digit-sequence の後にドットと別の digit-sequence (1.0 または .12) が続く |
| exponent-part | - | 浮動小数点リテラルと同じで、文字 e または文字 E の後にオプションの符号、その後に digit-sequence が続く |
| character-literal | - | 文字リテラルと同じ |
| string-literal | - | 文字列リテラルと同じで、生文字列リテラルを含む |
| ud-suffix | - | 識別子であり、リテラル演算子またはリテラル演算子テンプレートの宣言によって導入される (後述のリテラル演算子を参照) |
| (C++14以降) |
あるトークンがユーザー定義リテラル構文と通常のリテラル構文の両方に一致する場合、それは通常のリテラルとみなされます (つまり、123LL の LL をオーバーロードすることはできません)。
コンパイラが ud-suffix X を持つユーザー定義リテラルに遭遇すると、operator""X という名前の関数を求めて非修飾名前探索を実行します。探索で宣言が見つからない場合、プログラムは不適格です。それ以外の場合、
|
a) オーバーロード集合に、str が整形式テンプレート引数である非型テンプレートパラメータを持つ文字列リテラル演算子テンプレートが含まれる場合、ユーザー定義リテラル式は関数呼び出し operator ""X<str>() として扱われます。 |
(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 }
変換フェーズ6で文字列リテラルの連結が行われるとき、ユーザー定義文字列リテラルも連結され、連結の目的のために ud-suffix は無視されます。ただし、連結されるすべてのリテラルには1つのサフィックスのみが現れる場合があります。
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) }
[編集] リテラル演算子
ユーザー定義リテラルによって呼び出される関数は、リテラル演算子 (または、テンプレートの場合はリテラル演算子テンプレート) と呼ばれます。これは、以下の制限を除き、他の関数または関数テンプレートと同様に名前空間スコープで宣言されます (フレンド関数、関数テンプレートの明示的インスタンス化または特殊化、または using 宣言によって導入されることもあります)。
この関数の名前は、以下の2つの形式のいずれかをとることができます。
operator "" identifier |
(1) | (非推奨) | |||||||
operator user-defined-string-literal |
(2) | ||||||||
| identifier | - | この関数を呼び出すユーザー定義リテラルの ud-suffix として使用する識別子 |
| user-defined-string-literal | - | "" という文字シーケンスの後にスペースなしで、ud-suffix となる文字シーケンスが続く |
ud-suffix はアンダースコア _ で始まる必要があります。アンダースコアで始まらない接尾辞は、標準ライブラリによって提供されるリテラル演算子のために予約されています。また、二重アンダースコア __ を含めることはできません。そのような接尾辞も予約されています。
リテラル演算子がテンプレートの場合、空のパラメータリストを持ち、テンプレートパラメータは1つだけでなければなりません。それは、要素型が char である非型テンプレートパラメータパックでなければなりません (この場合、数値リテラル演算子テンプレートとして知られます)。
template<char...> double operator ""_x();
|
または、クラス型の非型テンプレートパラメータ (この場合、文字列リテラル演算子テンプレートとして知られます)。 struct A { constexpr A(const char*); }; template<A a> A operator ""_a(); |
(C++20以降) |
リテラル演算子には、以下のパラメータリストのみが許可されます。
( const char* ) |
(1) | ||||||||
( unsigned long long int ) |
(2) | ||||||||
( long double ) |
(3) | ||||||||
( char ) |
(4) | ||||||||
( wchar_t ) |
(5) | ||||||||
( char8_t ) |
(6) | (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) | (C++20以降) | |||||||
( const char16_t*, std::size_t ) |
(12) | ||||||||
( const char32_t*, std::size_t ) |
(13) | ||||||||
デフォルト引数は許可されません。
C 言語リンケージは許可されません。
上記以外の制限として、リテラル演算子およびリテラル演算子テンプレートは通常の関数(および関数テンプレート)であり、inlineまたはconstexprで宣言でき、内部または外部リンケージを持ち、明示的に呼び出すことができ、アドレスを取得でき、その他もろもろです。
#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() {}
[編集] 注記
ユーザー定義リテラルの導入以降、先行する文字列リテラルの後にスペースなしで固定幅整数型用のフォーマットマクロ定数を使用するコードは無効になりました。std::printf("%"PRId64"\n",INT64_MIN); は std::printf("%" PRId64"\n",INT64_MIN); に置き換える必要があります。
最長一致のため、p, P,(C++17以降) e および E で終わるユーザー定義整数および浮動小数点リテラルは、演算子 + または - が続く場合、ソースコード内で演算子と空白または括弧で区切る必要があります。
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
同じことが、整数または浮動小数点ユーザー定義リテラルに続くドット演算子にも当てはまります。
#include <chrono> using namespace std::literals; auto a = 4s.count(); // Error auto b = 4s .count(); // OK auto c = (4s).count(); // OK
さもなければ、単一の無効なプリプロセス数トークン(例: 1.0_E+2.0 や 4s.count)が形成され、コンパイルエラーとなります。
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_user_defined_literals |
200809L |
(C++11) | ユーザー定義リテラル |
[編集] キーワード
[編集] 例
#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'; }
出力
1.570796 123 0x123ABC abcabc
[編集] 標準ライブラリ
以下のリテラル演算子は標準ライブラリで定義されています。
| インライン名前空間
std::literals::complex_literals で定義されています。 | |
| 純虚数を表す std::complex リテラル (関数) | |
| インライン名前空間
std::literals::chrono_literals で定義 | |
| (C++14) |
時間を表す std::chrono::duration リテラル (関数) |
| (C++14) |
分を表す std::chrono::duration リテラル (関数) |
| (C++14) |
秒を表す std::chrono::duration リテラル (関数) |
| (C++14) |
ミリ秒を表す std::chrono::duration リテラル (関数) |
| (C++14) |
マイクロ秒を表す std::chrono::duration リテラル (関数) |
| (C++14) |
ナノ秒を表す std::chrono::duration リテラル (関数) |
| (C++20) |
特定の年を表す std::chrono::year リテラル (関数) |
| (C++20) |
月の日を表す std::chrono::day リテラル (関数) |
| インライン名前空間
std::literals::string_literals 内で定義 | |
| (C++14) |
文字配列リテラルを basic_string に変換する(function) |
| インライン名前空間
std::literals::string_view_literals で定義されています。 | |
| (C++17) |
文字配列リテラルのstring viewを作成する (function) |
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 1473 | C++11 | "" と ud-suffix の間の空白は リテラル演算子の宣言で必須だった |
オプションになった |
| CWG 1479 | C++11 | リテラル演算子はデフォルト引数を持つことができた | 禁止された |
| CWG 2521 | C++11 | operator"" _Bq は予約済み識別子 _Bq を使用しているため、不適格だった(診断は必須ではなかった) |
リテラル演算子の構文を非推奨化 "" と ud-suffix の間の空白を持つ |