move 函数是将任意类型的左值转为其类型的右值引用。
C++
template <typename T>
typename remove_reference<T>::type&& move(T&& t)
{
return static_cast<typename remove_reference<T>::type &&>(t);
}
首先需要了解一下,引用折叠原理:
再次详细描述 move 函数的处理流程:
remove_reference 主要作用是解除类型中引用并返回变量的实际类型。
C++
//原始的,最通用的版本
template <typename T> struct remove_reference{
typedef T type; //定义 T 的类型别名为 type
};
//部分版本特例化,将用于左值引用和右值引用
template <class T> struct remove_reference<T&> //左值引用
{ typedef T type; }
template <class T> struct remove_reference<T&&> //右值引用
{ typedef T type; }
//举例如下,下列定义的a、b、c三个变量都是int类型
int i;
remove_refrence<decltype(42)>::type a; //使用原版本,
remove_refrence<decltype(i)>::type b; //左值引用特例版本
remove_refrence<decltype(std::move(i))>::type b; //右值引用特例版本
forward 保证了在转发时左值右值特性不会被更改,实现完美转发。主要解决引用函数参数为右值时,传进来之后有了变量名就变成了左值。比如如下代码:
C++
#include <iostream>
using namespace std;
template<typename T>
void fun(T&& tmp)
{
cout << "fun rvalue bind:" << tmp << endl;
}
template<typename T>
void fun(T& tmp)
{
cout << "fun lvalue bind:" << tmp << endl;
}
template<typename T>
void test(T&& x) {
fun(x);
fun(std::forward<T>(x));
}
int main()
{
int a = 10;
test(10);
test(a);
return 0;
}
/*
fun lvalue bind:10
fun rvalue bind:10
fun lvalue bind:10
fun lvalue bind:10
*/
参数 x 为右值,到了函数内部则变量名则变为了左值,我们使用 forward 即可保留参数 x 的属性。
forward 函数实现如下:
C++
/**
* @brief Forward an lvalue.
* @return The parameter cast to the specified type.
*
* This function is used to implement "perfect forwarding".
*/
template<typename _Tp>
constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type& __t) noexcept
{ return static_cast<_Tp&&>(__t); }
/**
* @brief Forward an rvalue.
* @return The parameter cast to the specified type.
*
* This function is used to implement "perfect forwarding".
*/
template<typename _Tp>
constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
{
static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument"
" substituting _Tp is an lvalue reference type");
return static_cast<_Tp&&>(__t);
}
forward 函数的处理流程:
第一个,接受的参数是左值引用,只能接受左值。
第二个,接受的参数是右值引用,只能接受右值。
根据引用折叠的原理:
如果传递的是左值,_Tp 推断为 T &,则返回变成static_cast<T& &&>,也就是 static_cast<T&>,所以返回的是左值引用。
如果传递的是右值,_Tp 推断为 T&& 或者 T,则返回变成 static_cast<T && &&>,所以返回的是右值引用。
以下示例代码就可以观察到 move 与 forward 的原理区别:
C++
#include <iostream>
using namespace std;
typedef int& lref;
typedef int&& rref;
void fun(int&& tmp)
{
cout << "fun rvalue bind:" << tmp << endl;
}
void fun(int& tmp)
{
cout << "fun lvalue bind:" << tmp << endl;
}
int main()
{
int a = 11;
int &b = a;
int &&c = 100;
fun(static_cast<lref &&>(b));
fun(static_cast<rref &&>(c));
fun(static_cast<int &&>(a));
fun(static_cast<int &&>(b));
fun(static_cast<int &&>(c));
return 0;
}
/*
fun lvalue bind:11
fun rvalue bind:100
阅读量:2107
点赞量:0
收藏量:0