コードでは、次の構成が表示されます。
const class_name obj_name{func()};
func() は、 というクラスのオブジェクトを返しますclass_name
。では、なぜ次の構造を使用しないのだろうかと思います。
const class_name obj_name = func();
コードでは、次の構成が表示されます。
const class_name obj_name{func()};
func() は、 というクラスのオブジェクトを返しますclass_name
。では、なぜ次の構造を使用しないのだろうかと思います。
const class_name obj_name = func();
const class_name obj_name{func()};
上記を書くことで、作者は統一された初期化構文(C++11 で導入された)に従おうとしています。これは、経験豊富なプログラマーでさえ偶然に陥ってしまう厄介な parseと最も厄介な parse によって引き起こされる問題を回避するためです。彼は、以下で説明するように、前述の解析の問題にときどき陥らないように、ベストプラクティスを脳に教え込もうとしています。
このことを考慮、
struct X { /*....*/ }; // some class
struct Y
{
Y();
Y(int i);
Y(X x);
};
今、これを書くことができます:
Y y(100); // declare an object y of type Y
これで 2 番目のコンストラクターが呼び出されますが、これで問題ありません。これまでのところ、大丈夫です!
しかし、偶然にも次のように書いています。
Y y();
(誤って)デフォルトのコンストラクターを呼び出すと考えています。しかし実際には、デフォルトのコンストラクターは呼び出されません。y
代わりに、引数を取らない関数を宣言し、 を返しますY
。これは、C++ では煩わしい解析と呼ばれます。
同様に、次のように書くこともできます (偶然)。
Y y(X());
X
その場で作成される型のオブジェクトを渡す 3 番目のコンストラクターを呼び出すと考えています。繰り返しますが、それは間違っています。代わりにy
、関数ポインタ (型 function は何もとらず return を取るX
) と returnを取る関数を宣言しますY
。これは、C++ で最も厄介な解析と呼ばれます。
したがって、統一された初期化構文により、このような問題がすべて回避されます。次のように記述できます。
Y y1{}; // invokes 1st constructor
Y y2{100}; // invokes 2nd constructor
Y y3{X{}}; // invokes 3rd constructor
同じ構文に従って、
Y { function_call() };
const class_name obj_name { func() }; // taken from your question!
それは均一であり、確かにベストプラクティスですよね?
それが役立つことを願っています。
C++11 の時点で、型を初期化するいくつかの方法を提供する均一な初期化機能が導入されました。
この場合、両方の構文がclass_name(class_name const&)
コピー コンストラクターを呼び出します (存在する場合)。したがって、実際の違いはありません。それは単なる好みの問題です。
{}
この場合、構文が常にこのように動作するとは限らないことに注意してください。適切な型の initialization_list コンストラクターがある場合は、そのコンストラクターが使用されます。そうでない場合、クラス要素は適切なコンストラクターを使用して初期化されます。
Most Vexing Parseの原則 (関数プロトタイプとして解釈できる可能性がある場合はそうなる) に当てはまる場合は、次のものが関数プロトタイプではないことをコンパイラーに伝えるために、2 つのうちのいずれかを使用する必要があります。
typename class_name obj_name(func());
class_name obj_name { func() };