生と調理済み

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 つの大きな欠点があります。

<オール>
  • 暗黙的に int に変換します。
  • 列挙子を外側のスコープに導入します。
  • 列挙子の型を定義できません。
  • 特に、特性 1 と 2 は、多くの場合、悪い驚きの原因となります。新しい厳密に型指定された列挙は、これらの問題を解決します。次の投稿でそれについて読んでください。