2016-10-14 7 views
15

次のコードは両方ClangGCC(トランクバージョン)によって拒否される:[class.copy]/32による関数の戻り値の型から派生した型のローカルオブジェクトを返すときに移動コンストラクタが選択されないのはなぜですか?

#include <memory> 

struct Base 
{ 
    Base() = default; 
    Base(Base const&) = delete; 
    Base(Base&&) = default; 
}; 

struct Derived : Base 
{ 
    Derived() = default; 
    Derived(Derived const&) = delete; 
    Derived(Derived&&) = default; 
};  

auto foo() 
    -> Base 
{ 
    Derived d;  
    return d; // ERROR HERE 
} 

When the criteria for elision of a copy/move operation are met, but not for an exception-declaration, and the object to be copied is designated by an lvalue, or when the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue

上記の文が解析されることを意図されている場合(copy elision criteria met && lvalue) || (id-expression designating an automatic object)として、this CWG defectが示すように、ここで最後の条件が適用されないのはなぜですか? ClangとGCCの両方にコンパイラのバグはありますか?

一方、文章が(copy elision criteria met && (lvalue || id-expression designating an automatic object))と解釈される場合、これはDRの価値がある誤解を招く言葉ではありませんか?

+0

return文が 'return Base {d}'に対応していませんか?それで、デザインによって禁止されるべきですか?少なくとも、それは私がC++標準への深い洞察がなければ、めったに期待していないものです。 – davidhigh

+3

@davidhigh:スライシングは言語によって禁止されていませんが、それには多くのユースケースはありません。例えば、 'Derived d'を実行できます。ベースb = std :: move(d); 'ここでのポイントは、 'd'をrvalueとして扱うかどうかです(つまり、' return std :: move(d) 'を書いたかのように)かどうかです。 –

+1

ありがとう、さらに質問:elisionをどこにコピーする必要がありますか?素朴に言えば、 'Base {std :: move(d)} 'ではなく' std :: move(Base {d})'に対応する必要があります。または? – davidhigh

答えて

9

[class.copy]/32続け:

[...] if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.

最初のオーバーロード解決は、右辺値としてdを治療、Base::Base(Base&&)を選択します。ただし、選択されたコンストラクタの最初のパラメータのタイプはDerived&&ではなく、Base&&なので、そのオーバーロードの解像度の結果は破棄され、dを左辺値として扱います。その第2のオーバーロード解決は、削除されたコピーコンストラクタを選択する。

+0

ああどうしたの?とにかく、このルールは絶対的で忌まわしい憎悪です。 – Griwes

+0

エラーメッセージ: "main.cpp:In function 'Base foo(): main.cpp:21:12:エラー:削除された関数' Base :: Base(const Base&) 'の使用 return d ; //ここでエラーが発生しました ^ main.cpp:6:5:注意:ここに宣言しました ベース(ベースconst&)=削除; ^ ~~~ – SChepurin

+0

誰かがルールの起源を知っているか、リチャード・スミスは説明しますか:D – Griwes

関連する問題