std::forward
右值引用类型是独立于值的,一个右值引用参数作为函数的形参,在函数内部再转发该参数的时候它已经变成一个左值,并不是他原来的类型。
如果我们需要一种方法能够按照参数原来的类型转发到另一个函数,这种转发类型称为完美转发。
forward可以保持实参的类型、左值右值、是否const
forward的原型大致如下
template< typename T > inline
T&& forward( typename std::remove_reference<T>::type& t ) noexcept {
return (static_cast<T&&>(t));
}
template< typename T > inline
T&& forward( typename std::remove_reference<T>::type&& t ) noexcept {
static_assert(!is_lvalue_reference<T>::value, "bad forward call");
return (static_cast<T&&>(t));
}
move原型
template <typename T>
typename std::remove_reference<T>::type&& move (T&& t) {
return static_cast<typename std::remove_reference<T>::type&&>(t);
}
示例:
template<typename T>
void print(T& t){
cout << "L " << endl;
}
template<typename T>
void print(T&& t){
cout << "R " << endl;
}
/*
参考官方解答 https://zh.cppreference.com/w/cpp/utility/forward
若对 wrapper() 的调用传递右值 int ,则推导 T 为 int (非int& 或 int&&),且 std::forward 确保将右值引用传递给 print。
若对 wrapper() 的调用传递 const 左值 int ,则推导 T 为 const int& ,且 std::forward 确保将 const 左值引用传递给 print。
若对 wrapper() 的调用传递非 const 左值 int ,则推导 T 为 int& ,且 std::forward 确保将非 const 左值引用传递给 print
*/
template<typename T>
void wrapper(T && v){ // v始终是左值
/*
进入该函数后,v就成了一个变量。无论它是具名右值,还是左值。
再往下调用函数传参,都把它当变量,无法把一个变量赋值给另一个右值。
如 int &&tmp = v; 错误的,不能把一个右值引用绑定到一个右值引用类型的变量上。
*/
print(v); //永远匹配上面的左值函数,打印L
print(std::forward<T>(v)); //返回类型是T&&,所以只和T有关,做引用折叠。只有T是类似int&时,才返回左值。
print(std::move(v)); //返回类型是T::type&&,永远是返回右值,匹配上面的右值函数,打印R
}
int main(){
wrapper(1); //L R R 左值 右值 右值
int x = 1;
wrapper(x); //L L R
wrapper(std::forward<int>(x)); //L R R
wrapper(std::forward<int&>(x)); //L L R
wrapper(std::forward<int&&>(x)); //L R R
wrapper(std::forward<const int>(x)); //L R R
auto &&y = x;
auto &&z = 3;
wrapper(y); //L L R
wrapper(z); //L L R
return 0;
}