Mae*_*tro 7 c++ perfect-forwarding
我已经了解如何std::move工作并实现我自己的版本仅供练习。现在我试图了解如何std::forward工作:
到目前为止,我已经实现了这一点:
#include <iostream>
template <typename T>
T&& forward_(T&& x)
{
return static_cast<T&&>(x);
}
/*template <typename T>
T&& forward_(T& x)
{
return static_cast<T&&>(x);
}*/
void incr(int& i)
{
++i;
}
void incr2(int x)
{
++x;
}
void incr3(int&& x)
{
++x;
}
template <typename T, typename F>
void call(T&& a, F func)
{
func(forward_<T>(a));
}
int main()
{
int i = 10;
std::cout << i << '\n';
call(i, incr);
std::cout << i << '\n';
call(i, incr2);
std::cout << i << '\n';
call(0, incr3); // Error: cannot bind rvalue reference of type int&& to lvalue of type int.
std::cout << "\ndone!\n";
}
Run Code Online (Sandbox Code Playgroud)
为什么我必须提供forward(T&)采用左值引用的重载版本?据我了解,转发引用可以根据其参数的类型产生左值或右值。因此,通常不需要将纯右值文字与采用右值引用类型的函数一起传递0给?!callincr3int&&forward<T>(T&)
如果我取消注释该forward_(T&)版本,它可以正常工作!?
我仍然很困惑:为什么如果我只使用该forward_(T&)版本,它是否适用于任何价值类别?那么让一个转发参考有forward_(T&&)什么意义呢?
如果我取消注释采用左值引用的版本T&和采用转发引用的版本,T&&那么代码工作正常,并且我在两者中添加了一些消息以检查调用了哪个。结果是那个T&&从不叫!
template <typename T>
T&& forward_(T& x)
{
std::cout << "forward_(T&)\n";
return static_cast<T&&>(x);
}
template <typename T>
T&& forward_(T&& x)
{
std::cout << "forward_(T&&)\n";
return static_cast<T&&>(x);
}
Run Code Online (Sandbox Code Playgroud)
我的意思是在上面显示的驱动程序中运行相同的代码。
如果您手动指定(而不是让编译器推断它),则引用T&&将不再是转发引用。T如果T不是左值引用,则为T&&右值引用并且不接受左值。
例如,如果你这样做forward_<int>(...),则该参数是右值引用并且...只能是右值。
但如果您这样做forward_(...),则该参数是转发引用,并且...可以具有任何值类别。(虽然这样称呼它是没有意义的,因为forward_(x)它将具有与其自身相同的值类别x。)