13

この質問では、POD と集約とは何かを既にカバーしており、集約の初期化に関するいくつかの例を提供しています。

ここでの質問は、リストの初期化をどこで使用できるかということです。

また、 (より適切な用語がない場合)リストの割り当てはどこで使用できますか?

回答は、C++03 と C++11 の両方を扱い、それらの違いを強調する必要があります。

4

3 に答える 3

20

C++03

リストの初期化

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 では、変数を作成できるほぼすべての場所でリスト初期化を使用できます (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_listvector<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_liststd::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 を参照)
  • 代入の左オペランドがユーザー定義の代入演算子を持つクラス型である場合。この場合、演算子の引数を初期化するために波括弧初期化リストが使用されます ([expr.ass]/9 を参照)。これには、右側のオペランドの波括弧初期化リストoperator=(std::initializer_list<T>)の要素が に変換できる場合のような両方のケースが含まれます適切なコンストラクターなどを介して、演算子の引数の型に暗黙的に変換されます。Tstd::vector<int> vv = { 1, 2, 3 }

    struct A {
      int i;
      int j;
    };
    
    struct B {
      B& operator=(const A&);
    };
    
    int main() {
      B b;
      b = { 0, 1 };
    }
    

    ブレース初期化リストmainの最後の行で暗黙的に一時変数に変換され、その一時変数を引数としての代入演算子が呼び出されます。AB

于 2012-11-11T22:51:01.117 に答える
4

アグリゲートの初期化は、リストの初期化のサブセットであり、アグリゲートと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で導入されました。

于 2012-11-11T18:14:22.263 に答える
3

リスト初期化を使用して、動的に割り当てられた配列を初期化できます (C++11):

int * a = new int[3] {4, 3, 2};

C++03 では不可能な非常に気の利いた機能です。

于 2012-11-11T18:33:06.070 に答える