C++教科書/標準ライブラリ編/initializer list
編集はじめに
編集C++11から導入された初期化リスト(initializer list)は、コンテナや配列、ユーザー定義型の初期化を簡潔に記述できる新しい機能です。この機能はstd::initializer_list
クラステンプレートと関連する関数によって実装されています。本章ではstd::initializer_list
の使い方と内部動作を詳しく解説します。
initializerリストの基本
編集initializerリストとは
編集initializerリストとは、波カッコ{}
で囲まれた初期化子のリストのことです。以下は配列の初期化例です。
int arr[] = {1, 2, 3, 4, 5};
これまでは初期化子リストを使っていましたが、initializerリストではその初期化子リストを一時的なstd::initializer_list
オブジェクトとして扱えるようになりました。
initializerリストの使用例
編集std::vector
などのコンテナクラスには、initializerリストを直接渡して初期化できるコンストラクターが用意されています。
std::vector<int> v = {1, 2, 3, 4, 5}; // std::vector<int>のコンストラクターにinitializerリストを渡す
構造体やクラスのコンストラクター呼び出しでも使えます。
struct Point { int x, y; }; Point p = {1, 2}; // Pointのコンストラクターに{1, 2}を渡す
コンストラクターでのinitializer_listの活用
編集initializerリストを引数に取るコンストラクターを定義することで、convenientな初期化が可能になります。
class IntVector { public: IntVector(std::initializer_list<int> init) : v{init} {} private: std::vector<int> v; }; IntVector iv = {1, 2, 3, 4, 5}; // IntVectorのコンストラクターに{1, 2, 3, 4, 5}を渡す
initializer_listクラスの詳細
編集initializer_listクラステンプレートの定義
編集template <class E> class initializer_list { public: using value_type = E; using reference = const E&; using const_reference = const E&; using size_type = size_t; using iterator = const E*; using const_iterator = const E*; constexpr initializer_list() noexcept; constexpr size_t size() const noexcept; constexpr const E* begin() const noexcept; constexpr const E* end() const noexcept; };
initializer_listはテンプレートクラスで、要素型Eをテンプレート引数に取ります。メンバ型の定義から、このクラスはconstの配列を表すラッパーだと分かります。
メンバ型の説明
編集value_type
,reference
,const_reference
- 要素型EとEへの参照型
size_type
- 要素数を表すサイズ型(size_t)
iterator
,const_iterator
- 要素へのconstポインター
メンバ関数の説明
編集size()
- 要素数を返す
begin()
- 先頭要素を指すイテレーターを返す
end()
- 終端を指すイテレーターを返す
initializer_listへのアクセス
編集begin, end非メンバ関数
編集begin, end関数は標準ライブラリに特化された非メンバ関数版が用意されています。
template<class E> const E* begin(initializer_list<E> il) noexcept; template<class E> const E* end(initializer_list<E> il) noexcept;
これにより、ranged-forやアルゴリズムにinitializer_listを渡せます。
for (int x : {1,2,3,4,5}) { /* ... */ } std::cout << std::accumulate(std::begin({1,2,3}), std::end({1,2,3}), 0); // 出力:6
initializer_listの応用
編集コンテナ初期化での利用
編集std::vectorなどの多くのコンテナクラスには、initializer_listを引数に取るコンストラクター・代入演算子が用意されています。
std::vector<int> v{1, 2, 3, 4, 5}; // コンストラクター v = {6, 7, 8}; // 代入演算子
ユーザー定義型での利用
編集ユーザー定義型のコンストラクターにinitializer_listを受け取ることで、簡潔な初期化構文が可能になります。
class Point { int x, y; public: Point(std::initializer_list<int> list) { auto it = list.begin(); x = *it++; y = *it; } }; Point p = {1, 2}; // Pointのコンストラクターに{1, 2}を渡す
initializer_listを引数に取る関数
編集initializer_listを関数の引数に取ることもできます。これは可変長引数の代替として使えます。
void print(std::initializer_list<int> list) { for (int x : list) { std::cout << x << " "; } std::cout << endl; } print({1,2,3,4,5}); // 出力:1 2 3 4 5
まとめ
編集initializerリストはコンテナやユーザー定義型の初期化を簡潔に記述できる強力な機能です。std::initializer_list
クラスと関連する非メンバ関数によってこの機能が実現されています。一方で、実行時のオーバーヘッドが無視できないため、パフォーマンスが重要な場合には注意が必要です。初期化リストの利用を検討する際は、メリット・デメリットを十分に理解しましょう。