素朴で楽観的で、ああ.. C++ 11の統一された初期化構文の間違った見方
C++11 のユーザー定義型オブジェクトは{...}
、古い構文ではなく新しい構文で構築する必要があるため、コンストラクターのオーバーロードと同様のパラメーター(...)
を除きます (例: size ctor と 1 elem init_list ctor の比較)。std::initializer_list
std::vector
利点は次のとおりです。狭い暗黙の変換がなく、最も厄介な解析である一貫性 (?) に問題がありません。同じだと思っていたので問題はありませんでした(例を除いて)。
しかし、そうではありません。
純粋な狂気の物語
は{}
、既定のコンストラクターを呼び出します。
... 次の場合を除きます。
- デフォルトのコンストラクターが削除され、
- 他のコンストラクターは定義されていません。
では、むしろオブジェクトを値初期化するように見えますか?...オブジェクトがデフォルトのコンストラクターを削除した場合でも、オブジェクト{}
を作成できます。これは、削除されたコンストラクターの目的全体に勝っていませんか?
...次の場合を除く:
- オブジェクトには削除されたデフォルト コンストラクタがあり、
- 他のコンストラクターが定義されています。
その後、 で失敗しcall to deleted constructor
ます。
...次の場合を除く:
- オブジェクトには削除されたコンストラクターがあり、
- 他のコンストラクターが定義されておらず、
- 少なくとも非静的データ メンバー。
その後、フィールド初期化子が欠落して失敗します。
{value}
ただし、オブジェクトを構築するために使用できます。
これは最初の例外と同じかもしれません (値はオブジェクトに初期化されます)
...次の場合を除く:
- クラスには削除されたコンストラクターがあります
- クラス内のデフォルトで初期化された少なくとも 1 つのデータ メンバー。
次に、オブジェクトを作成すること{}
もできません。{value}
私はいくつかを逃したと確信しています。皮肉なことに、それは統一初期化構文と呼ばれています。繰り返しますが、UNIFORM初期化構文です。
この狂気は何ですか?
シナリオA
削除されたデフォルト コンストラクタ:
struct foo {
foo() = delete;
};
// All bellow OK (no errors, no warnings)
foo f = foo{};
foo f = {};
foo f{}; // will use only this from now on.
シナリオB
デフォルトのコンストラクターを削除し、他のコンストラクターを削除しました
struct foo {
foo() = delete;
foo(int) = delete;
};
foo f{}; // OK
シナリオC
デフォルトのコンストラクターを削除し、他のコンストラクターを定義
struct foo {
foo() = delete;
foo(int) {};
};
foo f{}; // error call to deleted constructor
シナリオD
既定のコンストラクターが削除され、他のコンストラクターは定義されておらず、データ メンバー
struct foo {
int a;
foo() = delete;
};
foo f{}; // error use of deleted function foo::foo()
foo f{3}; // OK
シナリオ E
デフォルト コンストラクターの削除、T コンストラクターの削除、T データ メンバーの削除
struct foo {
int a;
foo() = delete;
foo(int) = delete;
};
foo f{}; // ERROR: missing initializer
foo f{3}; // OK
シナリオ F
デフォルト コンストラクター、クラス内データ メンバー初期化子を削除
struct foo {
int a = 3;
foo() = delete;
};
/* Fa */ foo f{}; // ERROR: use of deleted function `foo::foo()`
/* Fb */ foo f{3}; // ERROR: no matching function to call `foo::foo(init list)`