ユーザー定義リテラルはC++にどのような新機能を追加しますか? 質問する

ユーザー定義リテラルはC++にどのような新機能を追加しますか? 質問する

C++11紹介するユーザー定義リテラルこれにより、既存のリテラル ( int、、、 )に基づいた新しいリテラル構文を導入できるようになり、任意の型でリテラル表現が可能になります。hexstringfloat

例:

// imaginary numbers
std::complex<long double> operator "" _i(long double d) // cooked form
{ 
    return std::complex<long double>(0, d); 
}
auto val = 3.14_i; // val = complex<long double>(0, 3.14)

// binary values
int operator "" _B(const char*); // raw form
int answer = 101010_B; // answer = 42

// std::string
std::string operator "" _s(const char* str, size_t /*length*/) 
{ 
    return std::string(str); 
}

auto hi = "hello"_s + " world"; // + works, "hello"_s is a string not a pointer

// units
assert(1_kg == 2.2_lb); // give or take 0.00462262 pounds

一見、これはとてもクールに見えますが、実際にどの程度適用できるのか疑問に思います。接尾辞を付け_AD_BC日付を作成することを考えたとき、演算子の順序が原因で問題があることがわかりました。は1974/01/06_AD最初に1974/01(単純なints として) 評価され、その後でのみ the が評価さ06_ADれます (8 進数のため、August と September は the なしで記述する必要があることは言うまで0もありません)。これは、演算子の評価順序が機能するように構文を にすることで回避できます1974-1/6_ADが、扱いにくいです。

私の質問は、要するに、この機能は正当化されると思いますか? C++ コードをより読みやすくするために、他にどのようなリテラルを定義したいですか?


2011年6月の最終草案に合わせて構文を更新しました

ベストアンサー1

一見すると、単純な構文糖のように見えます。

しかし、より深く見てみると、それは単なる構文上の甘味料以上のものであることがわかります。これは、C++ ユーザーのオプションを拡張し、個別の組み込み型とまったく同じように動作するユーザー定義型を作成します。この小さな「ボーナス」は、C++ に対する非常に興味深い C++11 の追加機能です。

C++ で本当に必要でしょうか?

過去数年間に書いたコードではあまり使われていないが、C++で使用しなかったからといって、それが面白くないというわけではない。別のC++開発者

C++ (そしておそらく C でも) では、コンパイラ定義のリテラルを使用して、整数を short または long 整数として、実数を float または double (または long double) として、文字列を通常の文字またはワイド文字として入力していました。

C++では、独自の型を作成することができました(つまりクラス)、潜在的にオーバーヘッド (インライン化など) はありません。演算子を型に追加して、同様の組み込み型のように動作させることが可能になりました。これにより、C++ 開発者は、言語自体に追加されたのと同じくらい自然に行列や複素数を使用できます。キャスト演算子を追加することもできます (これは通常、悪い考えですが、場合によっては適切な解決策になります)。

ユーザー型を組み込み型として動作させるには、ユーザー定義リテラルという機能がまだ欠けています。

ですから、これは言語の自然な進化だと思いますが、できるだけ完全なものにするためには、「型を作成し、それを組み込み型とできるだけ同じように動作させたい場合は、次のツールを使用します...

これは、ブール値、整数などを含むすべてのプリミティブを構造体にし、すべての構造体を Object から派生させるという .NET の決定と非常によく似ていると思います。この決定だけでも、Java が仕様にボックス化/アンボックス化ハックをどれだけ追加しても、プリミティブの操作に関して .NET は Java の範疇をはるかに超えるものになります。

C++ で本当に必要ですか?

この質問はあなた答えるには、ビャーネ・ストロウストルップでもハーブ・サッターでもC++標準委員会のメンバーでもない。これが理由だC++では選択肢がある、便利な表記法を組み込み型だけに限定することはありません。

もしあなた必要なら、それは歓迎すべき追加です。あなたいや、使わないでください。費用はかかりません。

機能がオプションである言語、C++ へようこそ。

むくみ???あなたのコンプレックスを見せてください!!!

肥大化と複雑化には違いがあります(しゃれです)。

ニールスが示したようにユーザー定義リテラルは C++ にどのような新しい機能を追加しますか?複素数を記述できることは、C と C++ に「最近」追加された 2 つの機能のうちの 1 つです。

// C89:
MyComplex z1 = { 1, 2 } ;

// C99: You'll note I is a macro, which can lead
// to very interesting situations...
double complex z1 = 1 + 2*I;

// C++:
std::complex<double> z1(1, 2) ;

// C++11: You'll note that "i" won't ever bother
// you elsewhere
std::complex<double> z1 = 1 + 2_i ;

現在、C99 の「double complex」型と C++ の「std::complex」型の両方で、演算子オーバーロードを使用して乗算、加算、減算などを行うことができます。

しかし、C99 では、組み込み型として別の型が追加され、組み込み演算子オーバーロードのサポートが追加されました。また、別の組み込みリテラル機能も追加されました。

C++ では、言語の既存の機能をそのまま使用し、リテラル機能が言語の自然な進化であると認識して、それを追加しました。

C では、別の型に対して同じ表記法の拡張が必要な​​場合、量子波動関数 (または 3D ポイント、または作業分野で使用している基本型) を組み込み型として C 標準に追加するためのロビー活動が成功するまでは、運が悪いことになります。

C++11 では、自分で実行できます。

Point p = 25_x + 13_y + 3_z ; // 3D point

膨満感がありますか?いいえC と C++ の両方の複素数がリテラル複素数値を表す方法を必要とすることからわかるように、その必要性は存在します。

設計ミスですか?いいえ拡張性を考慮して、他のすべての C++ 機能と同様に設計されています。

表記目的のみですか? いいえコードに型の安全性を追加することもできます。

たとえば、CSS 指向のコードを想像してみましょう。

css::Font::Size p0 = 12_pt ;       // Ok
css::Font::Size p1 = 50_percent ;  // Ok
css::Font::Size p2 = 15_px ;       // Ok
css::Font::Size p3 = 10_em ;       // Ok
css::Font::Size p4 = 15 ;         // ERROR : Won't compile !

そうすると、値の割り当てに強力な型付けを適用するのが非常に簡単になります。

危険ですか?

いい質問ですね。これらの関数は名前空間化できますか? もしできるなら、大当たりです!

ともかく、他の物と同様に、道具も不適切に使用すると自殺する可能性があるC は強力で、C の銃を誤って使用すると、自分の頭を撃ち落とすことができます。C++ には C の銃がありますが、メス、テーザー銃、その他ツールキットにあるあらゆるツールもあります。メスを誤って使用して出血死させることもできます。または、非常にエレガントで堅牢なコードを構築することもできます。

したがって、すべての C++ 機能と同様に、これは本当に必要でしょうか? これは、C++ で使用する前に答えなければならない質問です。必要でない場合は、コストはかかりません。ただし、本当に必要な場合は、少なくともこの言語はあなたを失望させません。

日付の例ですか?

あなたのエラーは、演算子を混在させていることにあるように思われます。

1974/01/06AD
    ^  ^  ^

/ は演算子なので、コンパイラがそれを解釈する必要があるため、これを避けることはできません。そして、私の知る限り、それは良いことです。

問題の解決策を見つけるには、リテラルを別の方法で記述します。たとえば、次のようになります。

"1974-01-06"_AD ;   // ISO-like notation
"06/01/1974"_AD ;   // french-date-like notation
"jan 06 1974"_AD ;  // US-date-like notation
19740106_AD ;       // integer-date-like notation

個人的には、整数と ISO 日付を選択しますが、それはあなたのニーズによって異なります。それが、ユーザーが独自のリテラル名を定義できるようにする主な目的です。

おすすめ記事