c – std :: forward如何获得正确的参数?
作者:互联网
考虑:
void g(int&);
void g(int&&);
template<class T>
void f(T&& x)
{
g(std::forward<T>(x));
}
int main()
{
f(10);
}
由于id-expression x是一个左值,并且std :: forward具有lvalues和rvalues的重载,为什么调用不会绑定到带有左值的std :: forward的重载?
template<class T>
constexpr T&& forward(std::remove_reference_t<T>& t) noexcept;
解决方法:
它确实绑定了一个左值的std :: forward的重载:
template <class T>
constexpr T&& forward(remove_reference_t<T>& t) noexcept;
它与T == int绑定.指定此函数返回:
static_cast<T&&>(t)
因为f中的T推导为int.所以这个重载将lvalue int强制转换为xvalue:
static_cast<int&&>(t)
因此调用g(int&&)重载.
总之,std :: forward的左值重载可以将其参数转换为lvalue或rvalue,具体取决于调用它的T的类型.
std :: forward的rvalue重载只能转换为rvalue.如果您尝试调用该重载并转换为左值,则程序格式错误(需要编译时错误).
超载1:
template <class T>
constexpr T&& forward(remove_reference_t<T>& t) noexcept;
捕获左值.
超载2:
template <class T> constexpr T&& forward(remove_reference_t<T>&& t) noexcept;
捕获rvalues(xvalues和prvalues).
重载1可以将其lvalue参数转换为lvalue或xvalue(后者将被解释为用于重载解析目的的rvalue).
Overload 2可以将其rvalue参数仅转换为xvalue(为了解决重载问题,它将被解释为rvalue).
过载2适用于标记为“B.应将右值作为右值转发”的情况,在N2951中.简而言之,这种情况可以:
std::forward<T>(u.get());
你不确定u.get()是否返回左值或右值,但是如果T不是左值引用类型,你想要移动返回的值.但是你不使用std :: move,因为如果T是左值引用类型,你不想从返回移动.
我知道这听起来有点做作.但是N2951在设置激励用例方面遇到了很大的麻烦,因为std :: forward应该使用显式提供的模板参数的所有组合以及普通参数的隐式提供的表达式类别来表现.
这不是一个简单的阅读,但模板和普通参数的每个组合对std :: forward的基本原理是在N2951.当时这在委员会中引起争议,并不容易出售.
std :: forward的最终形式并不完全是N2951提出的.但它确实通过了N2951中提出的所有六项测试.
标签:perfect-forwarding,c,c11,templates,rvalue-reference 来源: https://codeday.me/bug/20190930/1835847.html