次のコードは両方ClangとGCC(トランクバージョン)によって拒否される:[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の価値がある誤解を招く言葉ではありませんか?
return文が 'return Base {d}'に対応していませんか?それで、デザインによって禁止されるべきですか?少なくとも、それは私がC++標準への深い洞察がなければ、めったに期待していないものです。 – davidhigh
@davidhigh:スライシングは言語によって禁止されていませんが、それには多くのユースケースはありません。例えば、 'Derived d'を実行できます。ベースb = std :: move(d); 'ここでのポイントは、 'd'をrvalueとして扱うかどうかです(つまり、' return std :: move(d) 'を書いたかのように)かどうかです。 –
ありがとう、さらに質問:elisionをどこにコピーする必要がありますか?素朴に言えば、 'Base {std :: move(d)} 'ではなく' std :: move(Base {d})'に対応する必要があります。または? – davidhigh