Q.ちゃんと T&& を渡してるのになぜか T& の方が呼ばれるんだけどなんで?
void foo( cbar&& ); void foo( cbar& ); void baz( cbar&& bar ){ foo( bar ); // なぜか cbar& の方が呼ばれる }
A. cbar&& の方を呼んでもらうためには std::move が必要です
void baz( cbar&& bar ){ foo( std::move(bar)); // cbar&& の方が呼ばれる }
cbar&& の方を呼んで欲しいときは foo に rvalue を渡す必要があります
「foo に rvalue参照を渡す必要があります」ではないことに気を付けてください
「foo に rvalue を渡す必要があります」です
それが rvalue参照であるかどうかということと、それが rvalue であるかどうかということは同じではありません
foo に渡している bar には bar という名前が付いています
名前のついているものは lvalue です
ですから bar は lvalue です
bar は rvalue を参照している lvalue です
foo に lvalue を渡して呼ばれるのは cbar& の方です
lvalue を rvalue化するには std::move を使います
というわけで cbar&& の方を呼んでもらうためには std::move が必要です
テンプレート関数の実装の場合は少し事情が異なります
このような実装ではどちらも常に片方だけが呼ばれることになってしまって意図した通りにはなりません
template<typename T> inline void baz( T&& bar ){ foo( bar ); // cbar& の方が呼ばれる }
template<typename T> inline void baz( T&& bar ){ foo( std::move(bar)); // cbar&& の方が呼ばれる }
このような場合は std::forward を使います
template<typename T> inline void baz( T&& bar ){ foo( std::forward(bar)); // 適切な方が呼ばれる }