C++ ドラフト n4606 [dcl.init] 17.6 には、保証されたコピー省略に関する段落があります。
- 宛先の型が (おそらく cv 修飾された) クラス型の場合:
- 初期化式が prvalue であり、ソース型の cv 修飾されていないバージョンが宛先のクラスと同じクラスである場合、初期化式は宛先オブジェクトを初期化するために使用されます。[例:デフォルトのコンストラクターを
T x = T(T(T()));
呼び出して初期化します。—終了例]T
x
- [...]
操作方法についてのQ&Aもあります。
私が理解しているように、私が引用したルールは、イニシャライザ式が prvalue であり、ソース タイプの cv 非修飾バージョンが宛先のクラスと同じクラスである場合、ctor が関与しないことを保証します。そのため、コピーまたは移動 ctor の存在を確認する必要はありません。これにより、次のコードが C++17 で有効になります。
struct A {
A() {}
A(A const &) = delete;
A(A &&) = delete;
};
A f() { return A(); } // it's illegal in C++14, and suppose to be legal in C++17
しかし、私を夢中にさせているのは、c++ ドラフト n4606 のリスト初期化セクションに同様のルールが見つからないことです。私が見つけたのは([dcl.init.list] 3.6)です
[...]
- それ以外の場合、
T
がクラス型の場合、コンストラクターが考慮されます。適用可能なコンストラクターが列挙され、オーバーロード解決 (13.3、13.3.1.7) によって最適なコンストラクターが選択されます。引数のいずれかを変換するために縮小変換 (以下を参照) が必要な場合、プログラムは不適切な形式です。[...]
リスト初期化は最初に引用したルールよりも優先度が高いため、初期化子が初期化リストの場合は、リスト初期化セクションのルールを考慮する必要があります。ご覧のとおり、コンストラクターは、クラス type をリスト初期化するときに考慮されますT
。したがって、前の例に引き続き、
A ff() { return {A()}; }
C ++ 17で合法ですか?そして、誰かがリストの初期化で保証されたコピー省略がどのように機能するかを標準ドラフトが指定している場所を見つけることができますか?