yohhoyの日記

技術的メモをしていきたい日記

vector/arrayとUniform initialization+Initializer list

C++11標準ライブラリstd::vector, std::arrayにおいて Uniform initialization と Initializer list を組み合わせた場合に、N3337現在ではそれぞれ異なる表記が必要となる。2012年7月現在、CWG defect #1270に挙げられている*1

2013-11-16追記:CWG#1270が採択されたことで、本記事で言及する問題は解決済み。→id:yohhoy:20131116参照。

std::vector<int>   x0{1,2,3,4};
std::array<int, 4> y0{{1,2,3,4}};  // {}が二重に必要

本記事の内容はStack Overflowで見つけた質問と回答内容に基づく。

std::vector

vector<T>initialize_list<T>をとるコンストラクタ(initializer-list constructor)をもつクラスとして定義されている(8.5.4/p2, 23.3.6)。

クラス型vector<int>の変数x初期化はリスト初期化(list-initialization)*2であり、まずinitializer-list constructorがオーバーロード解決の候補となる(8.5/p16, 13.3.1.7/p1)。これによりコンストラクvector<int>::vector(initialize_list<int>)が呼び出される。

std::vector<int> x0{1,2,3,4};  // OK

std::array

array<T,N>は配列型T[N]などと同様にaggregate(アグリゲート; 集成体)と定義されている(23.3.2.1/p2)。つまりarray<T,N>にはinitialize_list<T>をとるコンストラクタは存在しない(8.5.1/p1)。

変数y1の初期化においてはaggregate initialization(=Cスタイルの配列/構造体初期化)が行われる(8.5.4/p3)。一方、変数y0初期化においては外側ブレースがdirect-initializationの指定(8.5/p15)、内側ブレースがlist-initializationの指定となる(8.5.4/p1)。

std::array<int, 4> y1 = {1,2,3,4};  // OK

std::array<int, 4> y0{{1,2,3,4}};   // OK

8.5.1/p11 脚注105にあるように、“aggregate initializationかつ入れ子aggregateの初期化*3” 以外のリスト初期化ではブレースを省略できない。

std::array<int, 4> y2{1,2,3,4};  // NG

std::array<int, 4> func()
{ return {1,2,3,4}; }  // NG
// return {{1,2,3,4}};とする必要あり

N3337 8.5.1/p1, p11(一部), 23.3.2.1/p2より引用。

1 An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal-initializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

11 In a declaration of the form
 T x = { a };
braces can be elided in an initializer-list as follows.105 If the initializer-list begins with a left brace, then the succeeding comma-separated list of initializer-clauses initializes the members of a subaggregate; it is erroneous for there to be more initializer-clauses than members. If, however, the initializer-list for a subaggregate does not begin with a left brace, then only enough initializer-clauses from the list are taken to initialize the members of the subaggregate; any remaining initializer-clauses are left to initialize the next member of the aggregate of which the current subaggregate is a member. (snip)
脚注105) Braces cannot be elided in other uses of list-initialization.

2 An array is an aggregate (8.5.1) that can be initialized with the syntax
 array<T, N> a = { initializer-list };
where initializer-list is a comma-separated list of up to N elements whose types are convertible to T.

関連URL

*1:http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2012/n3367.html#1270

*2:list-initialization is initialization of an object or reference from a braced-init-list.(8.5.4/p1)

*3:例:int x[2][2] = {{1,2},{3,4}}; の代わりに int x[2][2] = {1,2,3,4}; と記述できる。