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

トップページModern C++編

Modern C++編は作りかけで、更新が停止しています。代わりに、C++14 をベースにして、その他の方針についても見直しを行った、新C++編を作成しています。
Modern C++編は削除される予定です。

この章の概要 🔗

この章の概要です。


概要 🔗

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>

破棄 🔗

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

要素へのアクセス方法 🔗

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 の役割を考えると、変更できることに意味はないでしょう。

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};
}


解答ページはこちら

参考リンク 🔗


更新履歴 🔗

 コンパイラの対応状況について、対応している場合は明記しない方針にした。

 新規作成。



前の章へ (第7章 array)

次の章へ (第9章 イテレータ)

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

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る