この章の概要です。
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()
{
= {0, 1, 2, 3, 4};
IntInitList lst
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()
{
= {0, 1, 2, 3, 4};
IntInitList lst
for (IntInitList::value_type v : lst) {
std::cout << v << std::endl;
}
}
実行結果:
0
1
2
3
4
問題① 次のように呼び出すことができる関数 f を作成してください。
({0, 1, 2}); f
問題② 次のコードが動作するように、MyClass を実装してください。受け取った要素は、メンバ変数の std::vector に保存するようにしてください。
int main()
{
= {0, 1, 2};
MyClass mc = {9, 8, 7};
mc }
コンパイラの対応状況について、対応している場合は明記しない方針にした。
新規作成。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |