Modern C++編【標準ライブラリ】 第8章 initializer_list

先頭へ戻る

このエントリーをはてなブックマークに追加

この章の概要

この章の概要です。

概要

std::initializer_list は、クラスのオブジェクトを初期化する際に、リスト初期化の構文を使えるようにするためのクラステンプレートです。また、代入処理や関数の引数にも使われることがあり、{0, 1, 2} のような構文を使って、要素を渡すことができます。

std::initializer_list を使用するには、initializer_listという標準ヘッダをインクルードします。

リスト初期化がどんなものであるかについては、この章では解説していません。必要があれば、【言語解説】第16章を参照して下さい。

std::initializer_list は、次のように定義されています。

namespace std {
    template <class T>
    class initializer_list;
}

テンプレートパラメータ T は、要素の型です。要素とは、初期化リストに含まれる初期化子のことです。

std::initializer_list 自体の実装方法は規定されていませんが、通常は、初期化子の個数が収まる、初期化子と同じ型の配列を生成し、そこに初期化子を格納します。この配列を動的に確保すると無駄が大きいので、静的な領域か、自動領域(非static なローカル変数が使う領域)が使われます。そのため、処理負荷はそれほど気にする必要はありません。

生成と初期化

std::initializer_list にコンストラクタは、引数が無いデフォルトコンストラクタのみが定義されています。

#include <initializer_list>

int main()
{
    std::initializer_list<int> lst;  // 空の std::initializer_list
}

実行結果:




std::initializer_list は、リスト初期化の構文を使って生成することもできます。

これは、そのようなコンストラクタがある訳ではなく、いわば言語の文法機能の一環として存在しているものです。これができるからこそ、std::initializer_list型の引数を持ったコンストラクタを定義したクラスを、リスト初期化の構文でインスタンス化できます。

#include <initializer_list>

int main()
{
    std::initializer_list<int> lst = {0, 1, 2, 3, 4};
}

実行結果:



リスト初期化の構文から、std::initializer_list が生成できるということは、型推論(【言語解説】第20章)を使って、以下のように書けるということでもあります。

auto lst = {0, 1, 2, 3, 4};  // lst は std::initializer_list<int>

C++14 (constexprコンストラクタ)

C++14 でコンストラクタに constexpr が付加され、std::initializer_list がリテラル型(【言語解説】第24章)として使用できるようになりました。

VisualC++、Xcode ともに対応しています。

破棄

std::initializer_list のデストラクタは、コンパイラが生成するデフォルトのものです。これといって特別な処理を行いません。

メンバ型

std::initializer_list には、幾つかの型名が「公開」されたメンバとして定義されています。以下、表にまとめて紹介しますが、メンバ型の名前と、その意味だけがポイントとなります。具体的にどう定義されているかは、実装によって異なります。

まず、要素の型に関する定義があります。

メンバ型名 意味
value_type 要素の型。テンプレートパラメータ T のこと。
reference 要素の参照型。T&
const_reference 要素の const参照型。const T&

大きさに関する型があります。

メンバ型名 意味
size_type 主に要素数を意味する型。std::size_t。

イテレータに関する型があります。イテレータについては、「要素へのアクセス方法」の項で説明しています。

メンバ型名 意味
iterator イテレータ型。const T*
const_iterator constイテレータ型。const T*

iterator の方も const が付いており、const_iterator と同じになっています。std::initializer_list の要素は書き換えることができません。

サイズ

std::initializer_list のサイズ(要素数)は、sizeメンバ関数で取得できます。型は、std::initializer_list<>::size_type です。

#include <initializer_list>
#include <iostream>

int main()
{
    std::initializer_list<int> lst1;
    std::initializer_list<int> lst2 = {0, 1, 2, 3, 4};

    std::cout << lst1.size() << "\n"
              << lst2.size() << std::endl;
}

実行結果:

0
5

C++14 (sizeメンバ関数の constexpr化)

C++14 から、sizeメンバは、constexpr関数(【言語解説】第24章)になっています。

VisualC++、Xcode ともに対応しています。

要素へのアクセス方法

std::initializer_list の要素へアクセスするには、イテレータを使います。意外にも、[]演算子は使えません。

イテレータという概念に関する詳細は、第9章で改めて取り上げますが、要は、要素を指し示すもので、イテレータを経由して要素をアクセスできます。

std::initializer_list のイテレータは、std::vector(第6章)や std::array(第7章)と同様、beginメンバ関数endメンバ関数によって取得できます。std::vector や std::array のものと違って、これらのメンバ関数が返す型が iterator型とは宣言されておらず、const T*型で返されます。とはいえ、結局のところ同じ意味です。

クラスに属さない通常関数としての std::begin関数、std::end関数も存在しており、これらを使ってもイテレータを取得できます。詳細は、第9章で取り上げます。

また、std::initializer_list のイテレータは、常に const付きになっており、要素の値を変更することはできません。std::initializer_list の役割を考えると、変更できることに意味は無いでしょう。

C++14 (begin、endメンバ関数の constexpr化)

C++14 から、begin、endメンバ関数は、constexpr関数(【言語解説】第24章)になっています。

VisualC++、Xcode ともに対応しています。

beginメンバ関数と endメンバ関数の使用例です。

#include <initializer_list>
#include <iostream>

using IntInitList = std::initializer_list<int>;

int main()
{
    IntInitList lst = {0, 1, 2, 3, 4};

    const IntInitList::iterator itEnd = lst.end();
    for (IntInitList::iterator it = lst.begin(); it != itEnd; ++it) {
        std::cout << *it << std::endl;
    }
}

実行結果:

0
1
2
3
4

beginメンバ関数と endメンバ関数があるので、範囲for文(【言語解説】第3章、および第16章)を使うことができます。

#include <initializer_list>
#include <iostream>

using IntInitList = std::initializer_list<int>;

int main()
{
    IntInitList lst = {0, 1, 2, 3, 4};

    for (IntInitList::value_type v : lst) {
        std::cout << v << std::endl;
    }
}

実行結果:

0
1
2
3
4


練習問題

問題① 次のように呼び出すことができる関数 f を作成して下さい。

f({0, 1, 2});

問題② 次のコードが動作するように、MyClass を実装して下さい。受け取った要素は、メンバ変数の std::vector に保存するようにして下さい。

int main()
{
    MyClass mc = {0, 1, 2};
    mc = {9, 8, 7};
}


解答ページはこちら

参考リンク

更新履歴

'2017/12/6 新規作成。



前の章へ

次の章へ

Modern C++編のトップページへ

Programming Place Plus のトップページへ