c++引用包含左值引用和右值引用,因为引用都是变量,因此右值引用是左值。
左值指变量,右值指临时对象,字面值(16,“string”,13+2)。
当函数参数为T&&时(其中T时模板类型),是万能引用,传入参数是左值,T&&就变成左值引用,否则T&&变成右值引用。
template<typename T> void f(T&& t);
int i=1;//如果i传入,在f内还能改变i的值,故为左值引用。
去引用
std::remove_reference<T>
可以去除T的引用
T: int&& -->int;
T: int& --> int;
引用折叠
当模板类型是引用类型,而且函数参数是模板参数的引用的时候会发生引用折叠。
如void func(T&&) ---> 当T==int&
.
A&& & 折叠成 A&
A& & 折叠成 A&
A& && 折叠成 A&
A&& && 折叠成 A&&
也就是说引用类型和函数参数类型只要有一方为左值引用,就折叠成左值引用;如果双方都是右值引用,才折叠成右值引用。
move
move的作用是将 左值或者右值 强制转换成 右值引用类型。从而可以把左值或右值参数传入相应的函数。
template<class _T>
typename remove_reference<_T>::type&& move(T&& _Arg)
{
return static_cast<typename remove_reference<_T>::type<T>&&>(_Arg);
}
如何工作:
参数T&&保证左值(普通变量,左值引用,右值引用),右值(临时对象)都会进这个函数。
return:
普通变量 --> 临时对象(函数返回值)
临时对象 --> 临时对象(函数返回值)
左值引用 --> 右值引用
右值引用 --> 右值引用
forward
forward是完美转发,保持变量原有的左右值属性。右值参数–>赋值右值引用 --> 右值引用是变量(左值)–> 参数从右值变左值,调相应左值函数。
通过forward。右值参数–>赋值右值引用 --> 右值引用是变量(左值)–>forward将右值引用转成右值–> 参数为右值,调相应左值函数。
void f(int&& i)
{
cout << "r ref" << endl;
}
void f(int& i)
{
cout << "l ref" << endl;
}
void warp(int&& i)
{
f(i);
}
void warp1(int&& i)
{
f(forward<int>(i));
}
warp(13) --> l ref
warp1(13) --> r ref
源码
template<class _Ty>//func1
_NODISCARD constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept
{ // forward an lvalue as either an lvalue or an rvalue
return (static_cast<_Ty&&>(_Arg));
}
template<class _Ty>//func2
_NODISCARD constexpr _Ty&& forward(remove_reference_t<_Ty>&& _Arg) noexcept
{ // forward an rvalue as an rvalue
static_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
如何工作:
参数remove_reference_t<_Ty>&保证左值(普通变量,左值引用,右值引用)进函数1 。remove_reference_t<_Ty>&& 保证右值(临时对象)都会进函数2。
普通变量 -->经过 func1参数,变为左值引用–> 左值引用
左值引用 -->经过 func1参数,变为左值引用–> 左值引用
临时对象 -->经过 func2参数,变为右值引用–> 右值引用
右值引用 --> 经过 func2参数,变为右值引用–> 右值引用
理解就好,写代码时也不用考虑这么细吗?