名前空間
変種
操作

リスト初期化 (C++11およびそれ以降)

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (非推奨)
noexcept 指定子 (C++11)
例外
名前空間
指定子
decltype (C++11)
auto (C++11)
alignas (C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr (C++11)
ユーザ定義 (C++11)
ユーティリティ
属性 (C++11)
typedef 宣言
型エイリアス宣言 (C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

波括弧初期化子リストからオブジェクトを初期化します。

目次

[編集] 構文

[編集] 直接リスト初期化

T object { arg1, arg2, ... }; (1)
T { arg1, arg2, ... }; (2)
new T { arg1, arg2, ... } (3)
Class { T member { arg1, arg2, ... }; }; (4)
Class::Class() : member{arg1, arg2, ...} {... (5)

[編集] コピーリスト初期化

T object = {arg1, arg2, ...}; (6)
function( { arg1, arg2, ... } ) ; (7)
return { arg1, arg2, ... } ; (8)
object[ { arg1, arg2, ... } ] ; (9)
object = { arg1, arg2, ... } ; (10)
U( { arg1, arg2, ... } ) (11)
Class { T member = { arg1, arg2, ... }; }; (12)

リスト初期化は以下の状況で行われます。

  • 直接リスト初期化 (explicit なコンストラクタと非 explicit なコンストラクタの両方が考慮されます)
1) 波括弧初期化子リスト (波括弧で囲まれた式またはネストした波括弧初期化子リストのリスト (空でも構いません)) を用いた名前付き変数の初期化。
2) 波括弧初期化子リストを用いた名前のない一時オブジェクトの初期化。
3) 初期化子が波括弧初期化子リストであるような new 式を用いた動的記憶域期間を持つオブジェクトの初期化。
4) 非静的データメンバ初期化子で、等号を使用しない場合。
5) コンストラクタのメンバ初期化子リストで、波括弧初期化子リストが使用された場合。
  • コピーリスト初期化 (explicit なコンストラクタと非 explicit なコンストラクタの両方が考慮されますが、非 explicit なコンストラクタだけが呼ばれる可能性があります)
6) 等号の後に波括弧初期化子リストを用いた名前付き変数の初期化。
7) 波括弧初期化子リストが引数として使用された関数呼び出し式で。 リスト初期化が関数の引数を初期化します。
8) 波括弧初期化子リストが戻り値の式として使用された return で。 リスト初期化が返されるオブジェクトを初期化します。
9) ユーザ定義の operator[] を用いた添字式で、リスト初期化がそのオーバーロードされた演算子の引数を初期化する場合。
10) 代入式で、リスト初期化がオーバーロードされた演算子の引数を初期化する場合。
11) 関数キャスト式またはその他のコンストラクタ呼び出しで、コンストラクタ引数の場所に波括弧初期化子リストが使用された場合。 コピーリスト初期化がコンストラクタの引数を初期化します (ノート: この例の型 U はリスト初期化する対象の型ではありません。 U のコンストラクタの引数がその型です)。
12) 等号を使用する非静的データメンバ初期化子で。

[編集] 説明

T 型のオブジェクトのリスト初期化の効果は以下の通りです。

  • T が 集成体型であり、初期化子リストが同じ型または派生した型 (cv 修飾されていても構いません) の要素1個の場合、オブジェクトはその要素から初期化されます (コピーリスト初期化の場合はコピー初期化によって、直接リスト初期化の場合は直接初期化によって)。
  • そうでなく、 T が文字配列であり、初期化子リストが要素1個であり、その要素が適切な型の文字列リテラルの場合、配列はその文字列リテラルからいつも通りに初期化されます
(C++14およびそれ以降)
  • 波括弧初期化子リストが空で、 T がデフォルトコンストラクタを持つクラス型の場合は、値初期化が行われます。
(C++14以前)
  • そうでなく、波括弧初期化子リストが空で、 T がデフォルトコンストラクタを持つクラス型の場合は、値初期化が行われます。
(C++14およびそれ以降)
  • そうでなく、 Tstd::initializer_list の特殊化の場合、 T のオブジェクトは、波括弧初期化子リストから初期化された同じ型の prvalue (C++17以前)から、文脈に応じて直接初期化またはコピー初期化されます。
  • そうでなければ、以下の2つのフェーズで T のコンストラクタが考慮されます。
  • 前のステージでマッチがなかった場合、 T のすべてのコンストラクタが波括弧初期化子リストの要素によって構成される引数の集合に対するオーバーロード解決に参加します。 ただし縮小変換は許されないという制限が付きます。 このステージでコピーリスト初期化に対するベストマッチとして explicit コンストラクタが選択された場合、コンパイルは失敗します (単純なコピー初期化では explicit コンストラクタは一切考慮されないことに注意してください)。
  • そうでなく、 T が固定のベース型を持つスコープ付きまたはスコープなしいずれかの列挙型であり、波括弧初期化子リストが初期化子を1個だけ持ち、その初期化子からそのベース型への変換が縮小変換でなく、初期化が直接リスト初期化である場合、その列挙はその初期化子をそのベース型に変換した結果で初期化されます。
(C++17およびそれ以降)
  • そうでなく (T がクラス型でない)、波括弧初期化子リストが要素を1個だけ持ち、 T が参照型でないかその要素の型と互換な参照型であるかのいずれかの場合、 T直接初期化 (直接リスト初期化の場合) またはコピー初期化 (コピーリスト初期化の場合) されます。 ただし縮小変換は許されません。
  • そうでなく、 T がその要素の型と互換でない場合、その参照先の型の一時オブジェクトがリスト初期化され、その一時オブジェクトに参照が束縛されます (参照が非 const 左辺値参照の場合、これは失敗します)。
  • そうでなく、波括弧初期化子リストが要素を持たない場合、 T値初期化されます。

[編集] 縮小変換

リスト初期化は許される暗黙の変換を制限します。 以下の内容が禁止されます。

  • 浮動小数点型から整数型への変換。
  • long double から double または float への変換および double から float への変換。 ただし変換元が定数式でオーバーフローが発生しない場合は除きます。
  • 整数型から浮動小数点型への変換。 ただし変換元が定数式で、その値が変換先の型に正確に格納できる場合は除きます。
  • 整数型またはスコープなし列挙型から、元の型のすべての値を表現できない整数型への変換。 ただし変換元が定数式で、その値が変換先の型に正確に格納できる場合は除きます。

[編集] ノート

すべての初期化子節は、波括弧初期化子リスト内でそれより後にあるあらゆる初期化子節に対して先行配列されます。 これは、配列されない関数呼び出し式の引数とは対照的です

波括弧初期化子リストは式ではなく、そのため型がありません。 例えば decltype({1,2}) は ill-formed です。 型がないということは、テンプレート型推定が波括弧初期化子リストにマッチする型を推定できないということを意味し、そのため宣言 template<class T> void f(T); が与えられたとき、式 f({1,2,3}) は ill-formed です。 しかし、それ以外はテンプレート引数を推定でき、例えば std::vector<int> v(std::istream_iterator<int>(std::cin), {}) の場合、イテレータの型は第1引数によって推定され、それが第2引数の位置でも使用されます。 キーワード auto を用いた型推定については特別な例外があり、あらゆる波括弧初期化子リストは std::initializer_list として推定されます。

また、波括弧初期化子リストには型がないため、オーバーロードされた関数呼び出しへの引数として使用されたときは、オーバーロード解決のための特別なルールが適用されます。

集成体のコピー/ムーブは同じ型の単一要素の波括弧初期化子リストから直接的に初期化しますが、非集成体は initializer_list コンストラクタを最初に考慮します。

struct X {
    X() = default;
    X(const X&) = default;
};
 
struct Q {
    Q() = default;
    Q(Q const&) = default;
    Q(std::initializer_list<Q>) {}
};
 
int main() {
  X x;
  X x2 = X { x }; // コピーコンストラクタ (集成体初期化ではない)
  Q q;
  Q q2 = Q { q }; // 初期化子リストコンストラクタ (コピーコンストラクタではない)
}
(C++14およびそれ以降)

[編集]

#include <iostream>
#include <vector>
#include <map>
#include <string>
 
struct Foo {
    std::vector<int> mem = {1,2,3}; // 非静的メンバのリスト初期化
    std::vector<int> mem2;
    Foo() : mem2{-1, -2, -3} {} // コンストラクタでのメンバのリスト初期化
};
 
std::pair<std::string, std::string> f(std::pair<std::string, std::string> p)
{
    return {p.second, p.first}; // return 文でのリスト初期化
}
 
int main()
{
    int n0{};     // (ゼロへの) 値初期化
    int n1{1};    // 直接リスト初期化
    std::string s1{'a', 'b', 'c', 'd'}; // 初期化子リストコンストラクタの呼び出し
    std::string s2{s1, 2, 2};           // 普通のコンストラクタの呼び出し
    std::string s3{0x61, 'a'}; // 初期化子リストコンストラクタが (int, char) よりも優先されます
 
    int n2 = {1}; // コピーリスト初期化
    double d = double{1.2}; // 一時オブジェクトのリスト初期化、その後コピー初期化
 
    std::map<int, std::string> m = { // ネストしたリスト初期化
           {1, "a"},
           {2, {'a', 'b', 'c'} },
           {3, s1}
    };
 
    std::cout << f({"hello", "world"}).first // 関数呼び出しでのリスト初期化
              << '\n';
 
    const int (&ar)[2] = {1,2}; // 左辺値参照を一時配列に束縛します
    int&& r1 = {1}; // 右辺値参照を int の一時オブジェクトに束縛します
//  int& r2 = {2}; // エラー、右辺値を非 const 左辺値参照に束縛できません
 
//  int bad{1.0}; // エラー、縮小変換
    unsigned char uc1{10}; // OK
//  unsigned char uc2{-1}; // エラー、縮小変換
 
    Foo f;
 
    std::cout << n0 << ' ' << n1 << ' ' << n2 << '\n'
              << s1 << ' ' << s2 << ' ' << s3 << '\n';
    for(auto p: m)
        std::cout << p.first << ' ' << p.second << '\n';
    for(auto n: f.mem)
        std::cout << n << ' ';
    for(auto n: f.mem2)
        std::cout << n << ' ';
}

出力:

world
0 1 1
abcd cd aa
1 a
2 abc
3 abcd
1 2 3 -1 -2 -3

[編集] 欠陥報告

以下の動作変更欠陥報告は以前に発行された C++ 標準に遡って適用されました。

DR 適用先 発行時の動作 正しい動作
CWG 1467 C++14 same-type initialization of aggregates and char arrays was prohibited same-type initialization allowed
CWG 1467 C++14 std::initializer_list constructors had priority over copy constructors for single-element lists single-element lists initialize directly

[編集] 関連項目