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)によって最適なコンストラクターが選択されます。引数のいずれかを変換するために絞り込み変換(以下を参照)が必要な場合、プログラムの形式が正しくありません。[...]
リストの初期化は私が引用した最初のルールよりも優先度が高いため、イニシャライザーがイニシャライザーリストである場合は、リストの初期化セクションのルールを検討する必要があります。ご覧のとおり、クラスタイプをリスト初期化するときにコンストラクターが考慮されT
ます。したがって、前の例に続き、
A ff() { return {A()}; }
C ++ 17で合法ですか?そして、誰かが標準ドラフトがリストの初期化で保証されたコピーの省略がどのように機能するかを指定している場所を見つけることができますか?
保証された省略は、prvalue式を「オブジェクトを初期化する」ことを意味するように再定義することによって機能します。彼らはもはや一時的なものを構築しません。代わりに、一時変数は、prvalue式の特定の使用によって構築されます。
上記の「表現」という言葉の頻繁な使用に注意してください。1つの非常に重要な事実のために指摘します:braced-init-listは式ではありません。規格はこれについて非常に明確です。それは式ではない、とだけ表現はprvaluesすることができます。
確かに、エリジオンに関する規格のセクションを検討してください。
コピーの省略と呼ばれるこのコピー/移動操作の省略は、次の状況で許可されます。
- 式が非揮発性の自動オブジェクトの名前である場合、クラスの戻り値の型を持つ関数のreturnステートメントで...
- ..。
- 参照(12.2)にバインドされていない一時クラスオブジェクトが、同じcv-unqualifiedタイプのクラスオブジェクトにコピー/移動される場合
これらはすべて式を含みます(一時クラスオブジェクトは式です)。Braced-init-listsは式ではありません。
そのため、を発行した場合、が何であるかに関係なく、return {anything};
からの戻り値の構築はanything
省略されませんanything
。もちろん、標準によると、コンパイラはバグにより異なる場合があります。
そうは言っても、戻り値と同じ型のprvalue式がある場合、。return {prvalue};
だけでなく入力する可能性はほとんどありませんreturn prvalue;
。また、式が別のタイプである場合、とにかく省略の対象にはなりません。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加