以下では、カスタムリテラルについて説明します。これは非常に便利なツールですが、日常的な目的ではありません。
リテラルとは何ですか?
リテラルは、オブジェクトを作成する式です。 リテラルはC ++ 11だけでなく、C ++ 03にもありました。 たとえば、文字、文字列、実数などを作成するためのリテラルがあります。
'x'; // character "some"; // c-style string 7.2f; // float 74u; // unsigned int 74l; // long 0xF8; // hexadecimal number
これらはすべてリテラルです。 リテラルの概念で、私たちはそれを理解したと思います。 C ++ 11に戻りましょう。
C ++ 11のカスタムリテラル
上記のように、新しい標準はカスタムリテラルを作成するためのツールを提供します。 ユーザーリテラルには、 生のリテラルと組み込み型(調理済み)のリテラルの2つのカテゴリがあります。
ただし、C ++では接尾辞リテラルのみを作成できることに注意してください。 つまり、リテラルプレフィックス( 0xなど)またはプレフィックスサフィックス( ""など )の作成は失敗します。
数値型のリテラル
組み込み型のリテラルから始めましょう。 数値型のリテラルを作成するには、次の2つの署名のいずれかを使用する必要があります。
// OutputType operator "" _suffix(unsigned long long); // OutputType operator "" _suffix(long double);
リテラルの使用法は次のとおりです。
42_suffix; // OutputType operator "" _suffix(unsigned long long); 42.24_suffix; // OutputType operator "" _suffix(long double);
署名に注意してください。
- 整数のリテラルは、引数として
unsigned long long
を取ります - 実数のリテラルは引数として
long double
を取ります
これらのタイプは理由のために使用され、他のものと置き換えることはできません。 これらは必須であり、言語標準によって承認されています。
以下は、分を秒に変換するリテラルの例です。
unsigned long long operator "" _min(unsigned long long minutes) { return minutes * 60; } // ... std::cout << 5_min << std::endl; // 300
文字列型のリテラル
このタイプのリテラルを作成するには、次の署名のいずれかを使用する必要があります。
OutputType operator "" _suffix(const char* str, size_t size); OutputType operator "" _suffix(const wchar_t* str, size_t size); OutputType operator "" _suffix(const char16_t* str, size_t size); OutputType operator "" _suffix(const char32_t* str, size_t size);
署名は、文字列のタイプに応じて選択されます。
"1234"_suffix; // operator "" _suffix(const char* str, size_t size); u8"1234"_suffix; // operator "" _suffix(const char* str, size_t size); L"1234"_suffix; // operator "" _suffix(const wchar_t* str, size_t size); u"1234"_suffix; // operator "" _suffix(const char16_t* str, size_t size); U"1234"_suffix; // operator "" _suffix(const char32_t* str, size_t size);
Cスタイルの文字列を
std::string
列に変換するリテラルの例を以下に示します。
std::string operator "" s(const char* str, size_t size) { return std::string(str, size); } // ... std::cout << "some string"s.length() << std::endl;
生のリテラル
さて、最後に、生のリテラルの時間です。 生のリテラル署名は次のとおりです。
OutputType operator "" _suffix(const char* literalString);
このタイプのリテラルは、入力番号を文字ごとに解析する必要がある場合に役立ちます。 T..e。 この場合、数値は文字列として演算子に渡されます。 完全に明確でない場合は、以下のコードをご覧ください。
OutputType operator "" _x(unsigned long long); OutputType operator "" _y(const char*); 1234_x; // call: operator "" _x(1234); 1234_y; // call: operator "" _y("1234");
このタイプのリテラルを使用すると、2進数を10進数に変換するリテラルを作成できます。 たとえば、次のように:
unsigned long long operator "" _b(const char* str) { unsigned long long result = 0; size_t size = strlen(str); for (size_t i = 0; i < size; ++i) { assert(str[i] == '1' || str[i] == '0'); result |= (str[i] - '0') << (size - i - 1); } return result; } // ... std::cout << 101100_b << std::endl; // 44
生のリテラルには別のシグネチャがあります。 Variadic Templateのアプリケーションに基づいています:
template <char...> OutputType operator "" _b();
Variadic Templateベースのリテラルの利点は、コンパイル時に計算できることです。 同じ2進数から10進数へのリテラルは、次のように書き換えることができます。
template <char... bits> struct to_binary; template <char high_bit, char... bits> struct to_binary<high_bit, bits...> { static_assert(high_bit == '0' || high_bit == '1', "Not a binary value!"); static const unsigned long long value = (high_bit - '0') << (sizeof...(bits)) | to_binary<bits...>::value; }; template <char high_bit> struct to_binary<high_bit> { static_assert(high_bit == '0' || high_bit == '1', "Not a binary value!"); static const unsigned long long value = (high_bit - '0'); }; template <char... bits> constexpr unsigned long long operator "" _b() { return to_binary<bits...>::value; } // ... int arr[1010_b]; // std::cout << 101100_b << std::endl; // 44
注意深い読者は、 「生のリテラルと同じ名前の数字のリテラルの両方を作成したらどうなるでしょうか? コンパイラはどのリテラルを使用しますか?」 この問題の標準は正確な答えを提供し、コンパイラが次の順序でリテラルを使用しようとしていることを説明しています。
-
operator "" _x (unsigned long long)
またはoperator "" _x (long double)`
-
operator "" _x (const char* raw)
-
operator "" _x <'c1', 'c2', ... 'cn'>
ユーザー定義のリテラルがシステムリテラル(たとえば、 f )と一致する場合、システムリテラルが実行されることを知っておくと便利です。
long operator "" f(long double value) { return long(value); } // ... std::cout << 42.7f << std::endl; // 42.7
結論
Going Native 2012の BjörnStraustrupは、リテラルを使用する便利な例を示しました。 私は、コードの可読性を高めるという事実を明確に実証し、間違いの可能性も減らすように思えます。
Speed sp1 = 100m / 9.8s; // very fast for a human Speed sp2 = 100m / 9.8s2; // error (m/s2 is acceleration) Speed sp3 = 100 / 9.8s; // error (speed is m/s and 100 has no unit)
ユーザーリテラルメカニズムは、場合によっては便利なツールです。 どこでも使用する価値はありません。 リテラルは潜行性があるため、使用する前によく考えてください。
- コードの読みやすさを高め、コードを下げる方法。
- あなたの手の中とあなたと対戦する方法。
PS:
カスタムリテラルは、 gcc 4.7およびclang 3.1コンパイラでサポートされています。