ユニバーサルリファレンスに関する講義で、Scott Meyers(約40分)は、ユニバーサルリファレンスであるオブジェクトは、使用する前に実際の型に変換する必要があると述べました。つまり、ユニバーサル参照型のテンプレート関数がある場合は、std::forward
演算子と式を使用する前に使用する必要があります。そうしないと、オブジェクトのコピーが作成される可能性があります。
これについての私の理解は次の例にあります:
#include <iostream>
struct A
{
A() { std::cout<<"constr"<<std::endl; }
A(const A&) { std::cout<<"copy constr"<<std::endl; }
A(A&&) { std::cout<<"move constr"<<std::endl; }
A& operator=(const A&) { std::cout<<"copy assign"<<std::endl; return *this; }
A& operator=(A&&) { std::cout<<"move assign"<<std::endl; return *this; }
~A() { std::cout<<"destr"<<std::endl; }
void bar()
{
std::cout<<"bar"<<std::endl;
}
};
A getA()
{
A a;
return a;
}
template< typename T >
void callBar( T && a )
{
std::forward< T >( a ).bar();
}
int main()
{
{
std::cout<<"\n1"<<std::endl;
A a;
callBar( a );
}
{
std::cout<<"\n2"<<std::endl;
callBar( getA() );
}
}
予想どおり、出力は次のとおりです。
1
constr
bar
destr
2
constr
move constr
destr
bar
destr
問題は、なぜこれが必要なのかということです。
std::forward< T >( a ).bar();
std :: forwardなしで試しましたが、正常に動作しているようです(出力は同じです)。
同様に、なぜ彼は右辺値を持つ関数内でmoveを使用することを推奨するのですか?(答えはstd :: forwardの場合と同じです)
void callBar( A && a )
{
std::move(a).bar();
}
std::move
とは両方とも適切なタイプへのキャストであることを理解してstd::forward
いますが、これらのキャストは上記の例で本当に必要ですか?
ボーナス:その関数に渡されるオブジェクトのコピーを生成するために、例をどのように変更できますか?