ユーザ定義リテラル (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) | ||||||||
12_km など。0.5_Pa など。'c'_X など。"abd"_L や u"xyz"_M など。| decimal-literal | - | 整数リテラルの場合と同様、ゼロ以外の10進数字にゼロ個以上の10進数字が続いたもの |
| octal-literal | - | 整数リテラルの場合と同様、ゼロにゼロ個以上の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 | - | リテラル演算子またはリテラル演算子テンプレート宣言 (後述) によって導入された識別子。 プログラムによって導入されるすべての ud-suffix はアンダースコア文字 _ で始まらなければなりません。 標準ライブラリの ud-suffix はアンダースコアで始まりません。
|
整数および浮動小数点の数字の並びでは、任意の2つの数字の間に任意に区切り文字 ' を入れても構いません。 それらは無視されます。 |
(C++14以上) |
あるトークンがユーザ定義リテラルの構文にも普通のリテラルの構文にもマッチする場合、それは普通のリテラルであると仮定されます (つまり 123LL の LL をオーバーロードすることはできません)。
コンパイラがユーザ定義接尾辞 X を持つユーザ定義リテラルに遭遇したとき、 operator "" X という名前の関数を探して非修飾名の名前探索が行われます。 この探索で宣言が見付からない場合、プログラムは ill-formed です。 そうでなければ、
unsigned long long 型の引数を持つリテラル演算子が含まれていれば、ユーザ定義リテラル式は関数呼び出し operator "" X(nULL) として扱われます。 ただし n は ud-suffix を取り除いたリテラルです。operator "" X("n") として扱われます。operator "" X<'c1', 'c2', 'c3'..., 'ck'>() として扱われます。 ただし c1..ck は n の個々の文字です。long double 型の引数を持つリテラル演算子が含まれていれば、ユーザ定義リテラル式は関数呼び出し operator "" X(fL) として扱われます。 ただし f は ud-suffix を取り除いたリテラルです。operator "" X("f") として扱われます。operator "" X<'c1', 'c2', 'c3'..., 'ck'>() として扱われます。 ただし c1..ck は f の個々の文字です。str を ud-suffix を除いたリテラルとすると、
|
a) str が well-formed なテンプレート実引数である非型テンプレート引数をもつ文字列リテラル演算子テンプレートをオーバーロード集合が含む場合、ユーザ定義リテラル式は関数呼び出し operator "" X<str>() として扱われます。
|
(C++20以上) |
operator "" X (str, len) として扱われます。 ただし len は終端のヌル文字を除いた文字列リテラルの長さです。operator "" X (ch) として扱われます。 ただし ch は ud-suffix を取り除いたリテラルです。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; // operator "" _w(1.2L) を呼びます。
u"one"_w; // operator "" _w(u"one", 3) を呼びます。
12_w; // operator "" _w("12") を呼びます。
"two"_w; // エラー。 適用可能なリテラル演算子がありません。
}
翻訳フェーズ6で文字列リテラルの連結が行われるとき、ユーザ定義リテラルも同様に連結されます。 ud-suffix は連結の目的に対しては無視されます。 ただし連結されたすべてのリテラルに対して現れてよい接尾辞はひとつだけです。
int main() {
L"A" "B" "C"_x; // OK。 L"ABC"_x と同じ。
"P"_x "Q" "R"_y;// エラー。 2つの異なる ud-suffix (_x と _y)。
}
リテラル演算子
ユーザ定義リテラルによって呼ばれる関数はリテラル演算子 (またはそれがテンプレートの場合はリテラル演算子テンプレート) と言います。 これは名前空間スコープの他の関数または関数テンプレートとまったく同様に宣言されます (フレンド関数や関数テンプレートの明示的実体化または特殊化であってもよく、または using 宣言によって導入されても構いません)。 ただし以下の制限があります。
この関数の名前は以下の2つの形式のいずれかです。
operator "" identifier
|
|||||||||
operator user-defined-string-literal (C++14以上)
|
|||||||||
| identifier | - | この関数を呼ぶユーザ定義リテラルのための ud-suffix として使用する識別子。 アンダースコア _ で始まらなければなりません。 アンダースコアで始まらない接尾辞は標準ライブラリの提供するリテラル演算子用に予約されています。
|
| user-defined-string-literal | - | 文字シーケンス "" に ud-suffix になる文字シーケンスが空白なしで続いたもの。 この特別な構文は言語のキーワードおよび予約識別子を ud-suffix として使用することを可能とし、ヘッダ <complex> の operator ""if の宣言で使用されています。 この形式を使用することはユーザ定義リテラル演算子がアンダースコアで始まらなければならないというルールを変えるものではないことに注意してください。 operator ""if のような宣言は標準ライブラリの一部としてのみ現れることができます。 しかし、これはアンダースコアに大文字が続いたもの (通常は予約識別子です) の使用を可能とします。
|
リテラル演算子がテンプレートの場合は、空の引数リストを持たなければならず、テンプレート引数をひとつだけ持つことができます。 このテンプレート引数は、以下のような要素型が char の非型テンプレートパラメータパック (この場合は数値リテラル演算子テンプレートと言います)
template <char...> double operator "" _x();
|
であるか、以下のようなクラス型の非型テンプレート引数 (この場合は文字列リテラル演算子テンプレートと言います) struct A { A(const char *); auto operator<=>(const A&) const = default; };
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 として宣言したり、内部または外部リンケージを持たせたり、アドレスを取ったりできます。
void operator "" _km(long double); // OK。 1.0_km に対して呼ばれます。
std::string operator "" _i18n(const char*, std::size_t); // OK
template <char...> double operator "" _π(); // OK
float operator ""_e(const char*); // OK
float operator ""Z(const char*); // エラー。 接尾辞はアンダースコアで始まらなければなりません。
double operator"" _Z(long double); // エラー。 アンダースコアと大文字で始まる名前はすべて
// 予約されています。
double operator""_Z(long double); // OK。 _Z が予約されていても ""_Z は使用できます。
ノート
ユーザ定義リテラルが導入されたため、先行する文字列リテラルの後に空白がない固定幅の整数型のためのマクロ定数を使用するコードは無効になります。 例えば std::printf("%"PRId64"\n",INT64_MIN); は std::printf("%" PRId64"\n",INT64_MIN); に置き換える必要があります。
最長一致のために、 e、 E、 p および P (C++17以上) で終わるユーザ定義の整数および浮動小数点リテラルは、演算子 + または - が続くときは、ソースコード上でホワイトスペースまたは括弧で演算子を分離しなければなりません。
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; // エラー
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; // エラー
auto u = 1_p +2; // OK
同じことが整数または浮動小数点ユーザ定義リテラルに続くドット演算子にも適用されます。
#include <chrono>
using namespace std::literals;
auto a = 4s.count(); // エラー
auto b = 4s .count(); // OK
auto c = (4s).count(); // OK
さもなければ、単一の無効なプリプロセッサ数値トークン (1.0_E+2.0 や 4s.count など) が形成され、コンパイルが失敗する原因になります。
例
#include <iostream>
// 変換のために使用します
constexpr long double operator"" _deg ( long double deg )
{
return deg * 3.14159265358979323846264L / 180;
}
// カスタム型のために使用します
struct mytype
{
unsigned long long m;
};
constexpr mytype operator"" _mytype ( unsigned long long n )
{
return mytype{n};
}
// 副作用のために使用します
void operator"" _print ( const char* str )
{
std::cout << str;
}
int main(){
double x = 90.0_deg;
std::cout << std::fixed << x << '\n';
mytype y = 123_mytype;
std::cout << y.m << '\n';
0x123ABC_print;
}
出力:
1.570796
123
0x123ABC
標準ライブラリ
以下のリテラル演算子が標準ライブラリで定義されています。
名前空間
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 に変換します (関数) |
名前空間
std::literals::string_view_literals で定義 | |
(C++17) |
文字配列リテラルの文字列ビューを作成します (関数) |