LoginSignup
6
5

More than 5 years have passed since last update.

TIPS std::forward

Posted at

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&&だ

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5