std::forward(a)は単なるキャストである
使い方
template<class T>
void f(T&&a)
{
g(std::forward<T>(a));
}
これでf(???)はg(???)と同じように動く
ラムダ式なら
[](auto&&a){
g(std::forward<decltype(a)>(a));
}
なぜ必要か
template<class T>
void f(T&&a)
{
g(???);
}
fはgに対しaをどのように渡すべきであろうか
g(a)
f(std::move(x))
のように渡した時gに左辺値として渡されるのでよくない
例えばxがunique_ptrであったならばこの動作はmoveを期待するが、g(a)
のように渡してしまうとgから見てそれはmoveを許可されない値に見えるので期待通りにならない
g(std::move(a))
上と逆の理由でよくない
つまりmoveしてほしくない時にmoveされるとaが消失してしまうのでよくない
このナイーブな問題を解決するためにforwardは存在する
どのように動くか
f(???)はg(???)と同じように動く
f(x)
のようなとき
fにxが左辺値として渡されたとき
g(x)と同等に扱われる
T&& = A&
T == A&
となる
forward<T>(a)
はaをT&に変換し、T&であるので左辺値として扱われる
つまりg(x)と同等に扱われる
f(std::move(x))
f(make_value())
のようなとき
T&& == A&&
T == A
として扱われ
forward<T>(a)
はaをA&&に変換する。関数の戻り値なのでコレは右辺値として扱われる
つまりg(std::move(x))
g(make_value())
と同等に扱われる
よってf(???)はg(???)と同じように動く
forwardをつけるのをいつサボってよいか
最終的にgに渡すタイミングで参照と型が残っていればどうにかなるので自己管理の範疇でならサボっても悪くはない
decltype(a)はTではなくT&&でありforward<decltype(a)>
は大丈夫なのか
大丈夫なことになっている
T&& && == T&&だ