1.右值分为纯右值和将亡值,
纯右值:1、a+b
将亡值:临时对象、匿名对象
2.右值和左值的本质区别是能不能取地址
3.引用的使用
const 左值引用可以接收右值
右值引用不能接收左值,只接收右值
左值可以强制类型转换右值引用变成右值
右值引用类型的变量是左值,是可以取地址的(比如int&& a)
4.引用折叠:c++不允许引用的引用,会合并
& &&-》& && &-》& && &&-》&& & &-》&
5.万能引用
1.最经典是函数模板中的应用
#include <iostream>
template <typename T>
void wrapper(T &&u) { // 万能引用
func(std::forward<T>(u)); // 完美转发
}
class MyClass {};
void func(MyClass& a) { std::cout << "in func(MyClass&)\n"; }
void func(const MyClass& a) { std::cout << "in func(const MyClass&)\n"; }
void func(MyClass&& a) { std::cout << "in func(MyClass &&)\n"; }
int main(void) {
MyClass a;
const MyClass b;
func(a);
func(b);
func(MyClass());
std::cout << "----- Wrapper ------\n";
wrapper(a);
wrapper(b);
wrapper(MyClass());
return 0;
}
template<class T>
T&& forward(typename std::remove_reference<T>::type& t) noexcept {
return static_cast<T&&>(t);
}
template <class T>
T&& forward(typename std::remove_reference<T>::type&& t) noexcept {
return static_cast<T&&>(t);
}
在上面的例子中,wrapper万能引用的模板参数是推导给的,而forward完美转发的模板参数是显式给的
前三个func去找最好吃的,结果很明显。
1.看后三个,a是左值,wrapper的类型模板参数T被推导为MyClass&,forward的类型模板参数T给了MyClass&,在forward中会强制类型转换u为Myclass& &&,forward最后返回的u就是MyClass&,然后执行第一个func ,不用去管调了哪一个forward,反正最后强转的类型一样。
2.b是左值,wrapper的T推导是const myclass &,u的类型折叠后是const myclass&,forward的T给const myclass&,在forward中会强制类型转换u为const Myclass& &&,forward最后返回的u就是const MyClass&,执行第二个func。
3.myclass()是匿名对象,妥妥右值,wrapper的T推导是 myclass &&,u的类型折叠后是myclass&&,在forward中会强制类型转换u为 Myclass&& &&,forward最后返回的u就是 MyClass&&,调第三个func。如果没有完美转发,那直接使用u,u是右值引用类型是个左值,会调func(myclass&),forward相当于把左值u强转了一下,成了右值,会调func(myclass&&)
template <typename T>
typename remove_reference<T>::type&& move(T&& t)
{
return static_cast<typename remove_reference<T>::type&&>(t);
move可以将左值变为右值,本质不也是强转左值为右值引用类型使其变为右值
假设t是左值myclass类型,那这里万能引用T推导为myclass &,这里最后强转为myclass&&