C++11 のまとめ / TL;DR
- ブレースの省略の欠陥のため、例 0、2、6 は動作する必要はありません。ただし、コンパイラの最近のバージョンでは、その欠陥に対して提案された解決策が実装されているため、これらの例が機能します。
std::array
生の配列が含まれているかどうかは指定されていないためです。したがって、例 1、3、5、7 は機能する必要はありません。ただし、(実際には)機能しない標準ライブラリの実装については知りません。
- 例 4 は常に機能します。
std::array<int, 3> arr4 = {1, 2, 3};
バージョン 4 またはバージョン 2 (ブレースの省略を修正したもの) をお勧めします。これらは直接初期化され、動作する可能性が高い/必要なためです。
Sutter の AAA スタイルの場合、 を使用できますauto arrAAA = std::array<int, 3>{1, 2, 3};
が、これにはブレース省略の修正が必要です。
std::array
集約 [array.overview]/2 である必要があります。これは、ユーザー提供のコンストラクターがないことを意味します (つまり、default、copy、move ctor のみ)。
std::array<int, 3> arr0({1, 2, 3});
std::array<int, 3> arr1({{1, 2, 3}});
での初期化(..)
は直接初期化です。これには、コンストラクターの呼び出しが必要です。arr0
との場合arr1
、コピー/移動コンストラクターのみが実行可能です。したがって、これらの 2 つの例は、braced-init-list からテンポラリを作成し、std::array
それを destination にコピー/移動することを意味します。コピー/移動の省略により、たとえ副作用があっても、コンパイラはそのコピー/移動操作を省略できます。
注意: 一時変数は prvalues ですが、std::array
削除された場合など、移動 ctor が暗黙的に宣言されていない可能性があるため、コピーを呼び出す可能性があります (意味的に、コピー省略の前に)。
std::array<int, 3> arr6 = std::array<int, 3>({1, 2, 3});
std::array<int, 3> arr7 = std::array<int, 3>({{1, 2, 3}});
これらはコピー初期化の例です。次の 2 つの一時ファイルが作成されます。
- ブレース初期化リストを介して
{1, 2, 3}
コピー/移動コンストラクターを呼び出す
- 表現を通して
std::array<int, 3>(..)
後者の一時変数は、指定された宛先変数にコピー/移動されます。両方の一時的な作成は省略できます。
私の知る限り、実装はexplicit array(array const&) = default;
コンストラクターを記述でき、標準に違反することはありません。これにより、これらの例が不適切な形式になります。(この可能性は [container.requirements.general] によって除外されています。David Krauss に敬意を表します。この議論を参照してください。)
std::array<int, 3> arr2{1, 2, 3};
std::array<int, 3> arr3{{1, 2, 3}};
std::array<int, 3> arr4 = {1, 2, 3};
std::array<int, 3> arr5 = {{1, 2, 3}};
これが集約初期化です。std::array
それらはすべて、のコンストラクターを呼び出したり、std::array
(意味的に) 一時配列を作成したりせずに、 を「直接」初期化します。のメンバーは、std::array
コピー初期化によって初期化されます (以下を参照)。
ブレース省略のトピックについて:
C++11 標準では、ブレースの省略はフォームの宣言にのみ適用され、 には適用されT x = { a };
ませんT x { a };
。これは欠陥と見なされ、C++1y で修正される予定ですが、提案された解決策は標準の一部ではありません (DRWP ステータス、リンクされたページの上部を参照) T x { a };
。
したがって、std::array<int, 3> arr2{1, 2, 3};
(例 0、2、6) は厳密に言えば形式が正しくありません。私の知る限り、clang++ と g++ の最近のバージョンでは、ブレースの省略がT x { a };
既に許可されています。
例 6 では、std::array<int, 3>({1, 2, 3})
copy-initialization を使用しています。引数を渡すための初期化も copy-init です。ただし、ブレース省略の欠陥のある制限「フォームの宣言ではT x = { a };
」は、引数の受け渡しのブレース省略も禁止します。これは、宣言ではなく、確かにその形式ではないためです。
集約初期化のトピックについて:
Johannes Schaubがコメントで指摘しているように、次の構文 [array.overview]/2 でa を初期化できることが保証されているだけです。std::array
array<T, N> a = {初期化リスト};
そのことから、form でブレース省略が許可されている場合、T x { a };
次の構文を推測できます。
array<T, N> a {初期化リスト};
整形式で、同じ意味です。ただし、std::array
唯一のデータ メンバーとして raw 配列が実際に含まれているとは限りません ( LWG 2310も参照)。std::array<T, 2>
1 つの例として、2 つのデータ メンバーT m0
とがある部分的な特殊化が考えられますT m1
。したがって、次のように結論付けることはできません。
array<T, N> {{初期化リスト}};
整形式です。std::array
残念なことに、これは のブレースなしの一時的な省略を初期化する保証された方法がないという状況につながりT x { a };
、奇妙な例 (1、3、5、7) が機能する必要がないことも意味します。
最終的に を初期化するこれらの方法はすべて、std::array
集計の初期化につながります。これは、集合メンバーのコピー初期化として定義されます。ただし、ブレース初期化リストを使用したコピー初期化では、集約メンバーを直接初期化できます。例えば:
struct foo { foo(int); foo(foo const&)=delete; };
std::array<foo, 2> arr0 = {1, 2}; // error: deleted copy-ctor
std::array<foo, 2> arr1 = {{1}, {2}}; // error/ill-formed, cannot initialize a
// possible member array from {1}
// (and too many initializers)
std::array<foo, 2> arr2 = {{{1}, {2}}}; // not guaranteed to work
1 つ目は、initializer-clauses1
およびから配列要素を2
それぞれ初期化しようとします。このコピー初期化は、どちらが違法であるかfoo arr0_0 = 1;
と同等foo arr0_0 = foo(1);
です (削除された copy-ctor)。
2 番目には式のリストが含まれていませんが、初期化子のリストが含まれているため、[array.overview]/2 の要件を満たしていません。実際にstd::array
は、最初の initializer-clause から (のみ) 初期化される raw 配列データ メンバーが含まれています{1}
。2 番目の句{2}
は不正です。
3 番目には 2 番目とは逆の問題があります。配列データ メンバーがある場合は機能しますが、それは保証されません。