🧩
C++クイズ:std::vectorの初期化あれこれ
C++標準ライブラリのなかで最も利用頻度が高いであろう可変長配列std::vector
クラステンプレートは、その構築手段として多様なコンストラクタをオーバーロード提供しています。
さまざまなstd::vector
変数の初期化から、どんな可変長配列が生成されるか考えてみてください。もちろんC++標準ライブラリのリファレンスを参照しながらで構いませんよ!
- cpprefjp (日本語サイト)
- cppreference.com(英語サイト)
- C++17 DIS(N4659)(言語仕様そのもの;玄人向け)
レギュレーション: 本記事ではC++11以降〜最新のC++17言語までを前提とします。もうC++98/03しか知らないということはありませんよね?
出題編
C++11/14レベル(初級)
まずはstd::vector<int>
初期化を行う4問の出題です。ヒント:コンストラクタに与えている引数の個数、括弧の種類違い(()
と{}
)に留意してください。
std::vector<int> v1(2);
std::vector<int> v2{2};
std::vector<int> v3(3, 4);
std::vector<int> v4{3, 4};
C++17レベル(中級)
C++17ではクラステンプレートのテンプレート引数推論が導入され、std::vector
へのテンプレート引数明示を省略可能となりました。ここではstd::vector<int>
へと推論される追加4問の出題です。ヒント:必ずしもコンパイルできるわけではありません。
std::vector v5(2);
std::vector v6{2};
std::vector v7(3, 4);
std::vector v8{3, 4};
C++17レベル(上級)
まだまだ物足りないエキスパート向けの上級編として、追加の2問を用意しておきました。ヒント:型推論に注意!
std::vector v0{ 1, 2, 3, 4 };
std::vector v9 ( v0.begin(), v0.end() );
std::vector v10{ v0.begin(), v0.end() };
回答・解説編
C++11/14レベル(初級)
さっそく答え合わせとして、各行のコメントにて初期化結果を記載します。
std::vector<int> v1(2); // [0,0]
std::vector<int> v2{2}; // [2]
std::vector<int> v3(3, 4); // [4,4,4]
std::vector<int> v4{3, 4}; // [3,4]
-
v1
:コンストラクタに要素数をとるvector(size_type n)
が呼び出されます。各要素はデフォルト初期化されたint
型の値、つまり 要素0
×2
個 で初期化されます。 -
v2
:リスト初期化となるためvector(std::initalier_list<int> il)
が呼び出されます。つまり 要素2
のみで初期化されます。 -
v3
:コンストラクタに要素数と初期値をとるvector(size_type n, const int& value)
が呼び出されます。各要素は 初期値4
として3
個 の要素で初期化されます。 -
v4
:v2
同様にリスト初期化となるためvector(std::initalier_list<int> il)
が呼び出されます。つまり 要素3
と4
にて初期化されます。
C++17レベル(中級)
先レベルと同様に、各行のコメントにて初期化結果を記載します。
std::vector v5(2); // コンパイルエラー
std::vector v6{2}; // [2]
std::vector v7(3, 4); // [4,4,4]
std::vector v8{3, 4}; // [3,4]
-
v5
:int
型の引数2
から候補コンストラクタを探しますが、std::vector<T>
のテンプレート引数型T
を推論可能な候補は存在しません。よってコンパイルエラーとなります。- 引数を1個とる候補コンストラクタ
vector(const Allocator&)
,vector(size_type n)
は、実引数2
から要素型T
を推論できません。 - 引数を1個とる別の候補コンストラクタ
vector(const vector<T>&)
(コピーコンストラクタ),vector(vector<T>&&)
(ムーブコンストラクタ)は要素型T
情報を含むものの、int
型の実引数2
には適合しません。
- 引数を1個とる候補コンストラクタ
-
v6
,v7
,v8
:先レベルのv2
,v3
,v4
と同じコンストラクタが選択されます。特に面白いことは何もありません。
C++17レベル(上級)
最後の答え合わせです。各行のコメントにて初期化結果を記載します。
std::vector v0{ 1, 2, 3, 4 };
std::vector v9 ( v0.begin(), v0.end() ); // [1,2,3,4]
std::vector v10{ v0.begin(), v0.end() }; // [v0.begin(),v0.end()]
-
v9
:std::vector<int>::iterator
型の実引数v0.begin()
,v0.end()
から、テンプレートコンストラクタtemplate <class InputIterator> vector(InputIterator first, InputIterator last)
が選択されます。- 推論ガイド
template<class InputIterator> vector(InputIterator, InputIterator) -> vector<typename iterator_traits<InputIterator>::value_type>
より、テンプレートパラメータT
はtypename iterator_traits<std::vector<int>::iterator>::value_type
、つまり要素型int
が推論されます。
- 推論ガイド
-
v10
:リスト初期化となるためvector(std::initalier_list<std::vector<int>::iterator> il)
が優先されます。結果として要素型std::vector<int>::iterator
へと推論され、イテレータを要素にもつ可変長配列として初期化されます。
v10
の詳細解説は「シーケンスコンテナ×イテレータ・ペア×リスト初期化×推論ガイド=?」に譲ります。
Discussion