C++11 には、文字、C 文字列、整数、および浮動小数点数のユーザー定義リテラルがあります。整数と浮動小数点数の場合、生の形式とクックされた形式で利用できます。 C++14 のおかげで、2 進数、C++ 文字列、複素数、および時間単位のリテラルが組み込まれています。
4 つのユーザー定義リテラル
前回の投稿のユーザー定義リテラルの例の後、約束どおり、この投稿で詳細を提供します。私の意図を明確にするために、生のバリエーションと調理済みのバリエーションを含むリテラル型をここに示します:
表の読み方は?データ型 character の形式は character_suffix です。例は 's'_c です。コンパイラは、リテラル演算子 operator"" _c('s') を呼び出そうとします。この場合、文字は char です。 C++ はデータ型 char
に加えてサポートします データ型 wchar_t、char16_t、および char32_t。この型を C 文字列のベースとして使用できます。テーブルで char
を使用しました .この表は、コンパイラが C 文字列 "hi"_i18 をリテラル演算子 operator"" _i18n("hi",2) にマップすることを示しています。 2 は c 文字列の長さです。
コンパイラは、整数または浮動小数点数を整数 (unsigned long long int) または浮動小数点数 (long double) にマップできますが、それらを C 文字列にマップすることもできます。最初のバリアントは、調理済みフォームと呼ばれます。 2 番目のバリアントの生のフォーム。リテラル演算子がその引数を C 文字列として必要とする場合、コンパイラは raw 形式を使用します。そうでない場合は、調理済みのフォームを使用します。両方のバージョンを実装すると、コンパイラはクックされた形式を選択します。
確かに、最後の行には多くの混乱の可能性があります。したがって、次の表の署名の観点からすべてを要約します。最初の列はリテラル演算子の署名、2 番目の列はユーザー定義リテラルの型、最後の列はリテラル演算子の署名に適合するユーザー定義リテラルの例です。
もう一度計算する
投稿のユーザー定義リテラルで、週に平均何メートル車で行かなければならないかを計算しました。調理済み形式の long double 型のユーザー定義リテラルに基づいて計算を行いました。生の形式で計算を行うには、リテラル演算子を調整するだけです。
リテラル演算子の引数を C 型文字列から long double に変換することだけが必要です。これは、新しい関数 std::stold を使用すると非常に簡単に実行できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // unit.h #ifndef UNIT_H #define UNIT_H #include <distance.h> namespace Distance{ namespace Unit{ MyDistance operator "" _km(const char* k){ return MyDistance(1000* std::stold(k)); } MyDistance operator "" _m(const char* m){ return MyDistance(std::stold(m)); } MyDistance operator "" _dm(const char* d){ return MyDistance(std::stold(d)/10); } MyDistance operator "" _cm(const char* c){ return MyDistance(std::stold(c)/100); } } } #endif |
クラス MyDistance に触れなくてもかまいません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | // distance.h #ifndef DISTANCE_H #define DISTANCE_H #include <iostream> #include <ostream> namespace Distance{ class MyDistance{ public: MyDistance(double i):m(i){} friend MyDistance operator+(const MyDistance& a, const MyDistance& b){ return MyDistance(a.m + b.m); } friend MyDistance operator-(const MyDistance& a,const MyDistance& b){ return MyDistance(a.m - b.m); } friend MyDistance operator*(double m, const MyDistance& a){ return MyDistance(m*a.m); } friend MyDistance operator/(const MyDistance& a, int n){ return MyDistance(a.m/n); } friend std::ostream& operator<< (std::ostream &out, const MyDistance& myDist){ out << myDist.m << " m"; return out; } private: double m; }; } Distance::MyDistance getAverageDistance(std::initializer_list<Distance::MyDistance> inList){ auto sum= Distance::MyDistance{0.0}; for (auto i: inList) sum = sum + i ; return sum/inList.size(); } #endif |
また、メイン プログラムを変更する必要もありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | // average.cpp #include <distance.h> #include <unit.h> using namespace Distance::Unit; int main(){ std:: cout << std::endl; std::cout << "1.0_km: " << 1.0_km << std::endl; std::cout << "1.0_m: " << 1.0_m << std::endl; std::cout << "1.0_dm: " << 1.0_dm << std::endl; std::cout << "1.0_cm: " << 1.0_cm << std::endl; std::cout << std::endl; std::cout << "0.001 * 1.0_km: " << 0.001 * 1.0_km << std::endl; std::cout << "10 * 1_dm: " << 10 * 1.0_dm << std::endl; std::cout << "100 * 1.0cm: " << 100 * 1.0_cm << std::endl; std::cout << "1_.0km / 1000: " << 1.0_km / 1000 << std::endl; std::cout << std::endl; std::cout << "1.0_km + 2.0_dm + 3.0_dm + 4.0_cm: " << 1.0_km + 2.0_dm + 3.0_dm + 4.0_cm << std::endl; std::cout << std::endl; auto work= 63.0_km; auto workPerDay= 2 * work; auto abbrevationToWork= 5400.0_m; auto workout= 2 * 1600.0_m; auto shopping= 2 * 1200.0_m; auto distPerWeek1= 4*workPerDay-3*abbrevationToWork+ workout+ shopping; auto distPerWeek2= 4*workPerDay-3*abbrevationToWork+ 2*workout; auto distPerWeek3= 4*workout + 2*shopping; auto distPerWeek4= 5*workout + shopping; std::cout << "distPerWeek1: " << distPerWeek1 << std::endl; auto averageDistance= getAverageDistance({distPerWeek1,distPerWeek2,distPerWeek3,distPerWeek4}); std::cout<< "averageDistance: " << averageDistance << std::endl; std::cout << std::endl; } |
もちろん、結果は同じです。
C++14 の新しい組み込みリテラル
C++ は C++14 でいくつかの新しい組み込みリテラルを追加しました。これらは、2 進数、C++ 文字列、複素数、時間単位の組み込みリテラルです。まず、概要は次のとおりです。
いくつかの特別なルールを覚えておく必要があります。 2 進数は接頭辞 0b で始まります。組み込みリテラルにはアンダースコアがありません。これは、ユーザー定義のリテラルとは異なります。初めての C++ 文字列リテラルである C++14 での C++ サポート。これまでのところ、C++ は C 文字列リテラルのみをサポートしています。つまり、たとえば、C++ 文字列を初期化するには常に C 文字列リテラルを使用する必要があります。それはとても奇妙でした。時間リテラルは、暗黙的に単位を知っているため、非常に便利です。これらは std::chrono::duration 型です。
時間の基本単位は秒です。私の 16 歳の息子は、学校での日々がとても疲れているとよく不平を言います。もちろん、疑問が生じます。私の息子は、典型的な学校の一日に何秒必要ですか?プログラムが答えを出します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | // literals.cpp #include <iostream> #include <chrono> using namespace std::literals::chrono_literals; int main(){ std::cout << std::endl; auto schoolHour= 45min; auto shortBreak= 300s; auto longBreak= 0.25h; auto schoolWay= 15min; auto homework= 2h; auto schoolDayInSeconds= 2*schoolWay + 6 * schoolHour + 4 * shortBreak + longBreak + homework; std::cout << "School day in seconds: " << schoolDayInSeconds.count() << std::endl; std::cout << "School day in minutes: " << schoolDayInSeconds.count() / 60 << std::endl; std::cout << "School day in hours: " << schoolDayInSeconds.count() / 3600 << std::endl; std::cout << std::endl; |
このプログラムは完全に自明だと思います。接尾辞は十分に表現力があります。正しい追加を行うのは、コンパイラの仕事です。時間リテラルは、基本算術の加算、減算、乗算、除算、モジュロ演算をサポートしています。
自由に使える C++14 準拠のコンパイラがありません。本当に問題ではありません。 en.cppreference.com のオンライン コンパイラが答えを教えてくれます
私の息子は、学校に関連するすべてのタスクに 27300 秒かかります。これは、ドイツでの典型的な 1 日約 8 時間です。
次は?
C++ の従来の列挙 (enum) には 3 つの大きな欠点があります。
<オール>特に、特性 1 と 2 は、多くの場合、悪い驚きの原因となります。新しい厳密に型指定された列挙は、これらの問題を解決します。次の投稿でそれについて読んでください。