6

コピーおよび移動コンストラクターがいわゆるdone in で呼び出されないため、コンパイラーが以下のコードでコピー省略を行っていることを理解できます。実際の例を参照してください。copy-initializationmain()

#include <iostream>
struct S {
    S() = default;
    S(const S&) { std::cout << "copy ctor" << '\n'; }
    S(S&&) { std::cout << "move ctor" << '\n'; }
};

int main() {
    S s = S(); 
}

しかし、以下のように移動コンストラクターを削除すると、コードがコンパイルされない理由がわかりません。

#include <iostream>
struct S {
    S() = default;
    S(const S&) { std::cout << "copy ctor" << '\n'; }
    S(S&&) = delete;
};

int main() {
    S s = S(); 
}

§12.8/32 (N4140) には、この場合、コピー コンストラクターの使用または省略を禁止するものは見つかりません。これは、§12.8/32 で私の注意を喚起した文であり、オーバーロードの解決でコピー コンストラクターを考慮する必要があることを示しているようです。

最初のオーバーロードの解決が失敗したか実行されなかった場合、または選択されたコンストラクターの最初のパラメーターの型がオブジェクトの型への右辺値参照 (おそらく cv 修飾) でない場合、オブジェクトを左辺値。

編集

以下のTCによるコメントの 1 つから、コピーされるオブジェクトが右辺値で指定されている場合、コンパイラは、§12.8/32 に従って、コピー コンストラクターをコピーの候補と見なさないことを理解しています。とにかくコピーは省略されますが。つまり、最終結果はs、デフォルトのコンストラクターを使用したオブジェクトの構築になります。代わりに、この状況では、標準は (どこで??) コードの形式が正しくないことを義務付けています。このスキームに対する私の理解が完全に間違っていない限り、それは私には意味がありません。

4

1 に答える 1

2

これは、コピーの省略やコンストラクターに固有のものではありません。それは過負荷の解決です。

オーバーロードのペアがある場合:

void f( T&& rv );
void f( const T& lv );

f( T{} )オーバーロード解決ルールは、それが により適していると言っていf(T&&)ます。

コピー省略はコピーまたは移動を省略できますが、コードが明確に定義されている場合に限ります (コンパイラがコピー省略を実装しないことを選択した場合でも)。削除された関数を呼び出すように指定されているため、コードは明確に定義されていません。

于 2015-08-03T00:07:05.967 に答える