この質問では、POD と集約とは何かを既にカバーしており、集約の初期化に関するいくつかの例を提供しています。
ここでの質問は、リストの初期化をどこで使用できるかということです。
また、 (より適切な用語がない場合)リストの割り当てはどこで使用できますか?
回答は、C++03 と C++11 の両方を扱い、それらの違いを強調する必要があります。
この質問では、POD と集約とは何かを既にカバーしており、集約の初期化に関するいくつかの例を提供しています。
ここでの質問は、リストの初期化をどこで使用できるかということです。
また、 (より適切な用語がない場合)リストの割り当てはどこで使用できますか?
回答は、C++03 と C++11 の両方を扱い、それらの違いを強調する必要があります。
C++03 では、集計 (C++03 [dcl.init.aggr]) およびスカラー (C++03 [dcl.init]/13) 型に対してのみリスト初期化を使用できます。
int i = { 0 };
POD pod = { 0, 1, 2 };
C++03 のどこでも「リスト代入」を使用できませんでした。[expr.ass]/1 に示されている文法では、割り当ての右側に波括弧を付けることはできません。
C++11 では、変数を作成できるほぼすべての場所でリスト初期化を使用できます (C++11 の [dcl.init] と、リスト初期化が許可されているコンテキストを一覧表示する [dcl.init.list]/1 を参照してください)。 ) 例えば
struct Base { };
struct Class : Base
{
int mem{ 0 }; // init non-static data member
Class(int i)
: Base{} // init base class
, mem{i} // init member
{
int j{i}; // init local var
int k = int{0}; // init temporary
f( { 1 } ); // init function arg
int* p = new int{1}; // new init
// int k(int()); // most vexing parse, declares function
int k{ int{} }; // ok, declares variable
int i[4]{ 1,2,3,4 }; // init array
}
Class f(int i)
{
return { i }; // init return value
}
};
Class c{1}; // init global var
int
上記の初期化のほとんどはor の配列を宣言しint
ますが、同じ構文を使用してクラス型のコンストラクターを呼び出すことができます (Class
変数を構築する 2 行のように)
リスト初期化は、変数を初期化できるほぼすべてのコンテキストで有効であるだけでなく、C++11 の別の新機能であるstd::initializer_list
クラス テンプレートともうまく相互作用します。引数を取るコンストラクターには、任意の長さの値のリストを渡すことができます。コンストラクターは、 およびのメンバー関数をstd::initializer_list
介して反復処理できます。この新機能の主な利点は、コンテナを構築してから値を挿入するのではなく、一連の要素でコンテナを初期化できることです。begin()
end()
std::initializer_list
vector<int> v{ 0, 1, 2, 3, 4, 5 }
リスト初期化は波括弧初期化リスト内の要素にも使用できますMap m{ {a, b}, {c, d} }
。Map m{ Map::value_type(a, b), Map::value_type(c, d) }
リスト初期化が正しいことをしないのは、クラスに を受け取る別のコンストラクターがある場合に、コンストラクターを呼び出してクラス型を構築しようとするときだけですstd::initializer_list
。std::initializer_list
// attempts to create vector of 5 elements, [1,1,1,1,1]
// but actually creates a vector with two elements, [5,1]
std::vector<int> v{ 5, 1 };
これは、vector(size_type, const int&)
コンストラクターを呼び出すのではなく、コンストラクターを呼び出しませんvector(initializer_list<int>)
。
C++11 では、「リスト代入」を使用できます。
代入の左オペランドがユーザー定義の代入演算子を持つクラス型である場合。この場合、演算子の引数を初期化するために波括弧初期化リストが使用されます ([expr.ass]/9 を参照)。これには、右側のオペランドの波括弧初期化リストoperator=(std::initializer_list<T>)
の要素が に変換できる場合のような両方のケースが含まれます。適切なコンストラクターなどを介して、演算子の引数の型に暗黙的に変換されます。T
std::vector<int> v
v = { 1, 2, 3 }
struct A {
int i;
int j;
};
struct B {
B& operator=(const A&);
};
int main() {
B b;
b = { 0, 1 };
}
ブレース初期化リストmain
の最後の行で暗黙的に一時変数に変換され、その一時変数を引数としての代入演算子が呼び出されます。A
B
アグリゲートの初期化は、リストの初期化のサブセットであり、アグリゲートとPODのみに限定されます(参照した質問で説明されています)。どちらのタイプの初期化も中括弧とオプションでequalsを使用するため、初期化の時点で構文は同じように見えます。各形式の初期化を使用できる場所などの詳細については、 http ://en.cppreference.com/w/cpp/language/aggregate_initializationおよびhttp://en.cppreference.com/w/cpp/language/list_initializationを参照してください。
C ++ 03では、集約の初期化はequals(つまり、Tオブジェクト{arg1、arg2};Tオブジェクト={arg1、arg2};だけでは無効)でのみ使用できましたが、C ++ 11ではequalsなしで使用できます(つまり、 Tオブジェクト{arg1、arg2};有効になりました)。また、C ++ 11では、集約の初期化がわずかに変更され、集約の初期化で変換を絞り込むことができなくなりました。
集約初期化サブセットではないリスト初期化のサブセットは、C++11で導入されました。
リスト初期化を使用して、動的に割り当てられた配列を初期化できます (C++11):
int * a = new int[3] {4, 3, 2};
C++03 では不可能な非常に気の利いた機能です。