簡単なルールがあります。コピーの省略の条件が満たされている場合(変数が関数パラメーターである場合を除く)、右辺値として扱います。それが失敗した場合は、左辺値として扱います。それ以外の場合は、左辺値として扱います。
§12.8 [class.copy] p32
ソースオブジェクトが関数パラメーターであり、コピーされるオブジェクトが左辺値で指定されていることを除いて、コピー操作の省略基準が満たされている、または満たされる場合、コピーのコンストラクターを選択するためのオーバーロード解決は次のようになります。最初は、オブジェクトが右辺値で指定されているかのように実行されます。オーバーロード解決が失敗した場合、または選択したコンストラクターの最初のパラメーターのタイプがオブジェクトのタイプへの右辺値参照ではない場合(おそらくcv修飾)、オブジェクトを左辺値と見なして、オーバーロード解決が再度実行されます。[注:この2段階の過負荷解決は、コピーの省略が発生するかどうかに関係なく実行する必要があります。省略が実行されない場合に呼び出されるコンストラクターを決定し、呼び出しが省略された場合でも、選択されたコンストラクターにアクセスできる必要があります。—エンドノート]
例:
template<class T>
T f(T v, bool b){
T t;
if(b)
return t; // automatic move
return v; // automatic move, even though it's a parameter
}
次のコードには自動移動がないため、私はそのルールに個人的に同意するわけではありません。
template<class T>
struct X{
T v;
};
template<class T>
T f(){
X<T> x;
return x.v; // no automatic move, needs 'std::move'
}
私のこの質問も参照してください。