10

C++ ドラフト n4606 [dcl.init] 17.6 には、保証されたコピー省略に関する段落があります。

  • 宛先の型が (おそらく cv 修飾された) クラス型の場合:
    • 初期化式が prvalue であり、ソース型の cv 修飾されていないバージョンが宛先のクラスと同じクラスである場合、初期化式は宛先オブジェクトを初期化するために使用されます。[:デフォルトのコンストラクターをT x = T(T(T()));呼び出して初期化します。—終了例]Tx
    • [...]

操作方法についての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で合法ですか?そして、誰かがリストの初期化で保証されたコピー省略がどのように機能するかを標準ドラフトが指定している場所を見つけることができますか?

4

1 に答える 1

7

保証された省略は、「オブジェクトを初期化する」ことを意味するように prvalue 式を再定義することによって機能します。それらはもはや一時的なものを構築しません。代わりに、一時変数は prvalue 式の特定の用途によって構築されます。

上記の「式」という言葉が頻繁に使用されていることに注意してください。私がそれを指摘するのは、1 つの非常に重要な事実があるためです: ブレース初期化リストは式ではありません。基準はこれについて非常に明確です。これは式ではなく、prvalue にできるのは式だけです。

実際、省略に関する標準のセクションを検討してください。

コピー省略と呼ばれるこのコピー/移動操作の省略は、次の状況で許可されます。

  • クラスの戻り値の型を持つ関数の return ステートメントで、が非揮発性の自動オブジェクトの名前である場合...
  • ...
  • 参照 (12.2) にバインドされていない一時クラス オブジェクトが、同じ cv 非修飾型のクラス オブジェクトにコピー/移動される場合

これらはすべて式を含みます (一時的なクラス オブジェクトは式です)。ブレース初期化リストは式ではありません。

そのため、 を発行すると、何が何であれreturn {anything};、からの戻り値の構築はanything省略されませんanything。もちろん、標準によると。コンパイラはバグにより異なる場合があります。

そうは言っても、戻り値と同じ型の prvalue 式がある場合、return {prvalue};単にreturn prvalue;. また、式が別の型である場合は、省略の対象にはなりません。

于 2016-08-06T14:46:33.367 に答える