建设部咨询资质网站,泉州网上办事大厅,wordpress 修改站点,企业网站的建立标准文章目录 2. 右值引用和移动语义2.6 类型分类#xff08;实践中没什么用#xff09;2.7 引用折叠2.8 完美转发2.9 引用折叠和完美转发的实例 2. 右值引用和移动语义
2.6 类型分类#xff08;实践中没什么用#xff09;
C11以后#xff0c;进一步对类型进行了划分#x… 文章目录 2. 右值引用和移动语义2.6 类型分类实践中没什么用2.7 引用折叠2.8 完美转发2.9 引用折叠和完美转发的实例 2. 右值引用和移动语义
2.6 类型分类实践中没什么用
C11以后进一步对类型进行了划分右值被划分纯右值(pure value简称prvalue)和将亡值纯右值是指那些字面值常量或(表达式的返回值)求值结果相当于字面值或是一个不具名的临时对象。如 42、true、nullptr 或者类似 str.substr(1, 2)、str1 str2 传值返回函数调用或者aab 等。纯右值和将亡值C11中提出的C11中的纯右值概念划分等价于C98中的右值将亡值是指返回右值引用的函数的调用表达式和转换为右值引用的转换函数的调用表达(可以是强制类型转换)如move(x)、static_castX(x) - (X)x(其实是强制类型转化)左值被强转左值被move之后变为将亡值泛左值(generalized value简称glvalue)泛左值包含将亡值和左值有名字就是泛左值有名字且未被移动的就是左值有名字且被移动的就是将亡值没有名字且不可以被移动的就是纯右值纯右值在实践中可以被移动比如匿名对象的资源在函数内部被引用属性变为左值可以转移资源实践中将亡值和纯右值可以被移动
2.7 引用折叠 1. C中不能直接定义引用的引用如 int r i; 这样写会直接报错通过模板或 typedef中的类型操作可以构成引用的引用。 2. 引用折叠的规则右值引用的右值引用折叠成右值引用所有其他组合均折叠成左值引用。 3. 像f2函数一样传左值是左值引用,传右值是右值引用T x参数看起来是右值引用参数但是由于引用折叠的规则他传递左值时就是左值引用传递右值时就是右值引用这就是万能引用 4. Function(T t)函数模板程序中假设实参是int右值模板参数T的推导int实参是int左值模板参数T的推导int再结合引用折叠规则就实现了实参是左值实例化出左值引用版本形参的Function实参是右值实例化出右值引用版本形参的Function 5. 搞这么麻烦的东西其实是为了实现这个万能模版 引用折叠
int main()
{typedef int lref;typedef int rref;int n 0;// 引用折叠lref r1 n; // r1 的类型是 intlref r2 n; // r2 的类型是 intrref r3 n; // r3 的类型是 intrref r4 1; // r4 的类型是 int// 右值引用右值引用最终才是右值引用return 0;
}显示实例化
// 由于引用折叠限定f1实例化以后总是一个左值引用
templateclass T
void f1(T x)
{}// 由于引用折叠限定f2实例化后可以是左值引用也可以是右值引用
templateclass T
void f2(T x)
{}int main()
{int n 0;// 没有折叠-实例化为void f1(int x)f1int(n);f1int(0); // 报错// 折叠-实例化为void f1(int x)f1int(n);f1int(0); // 报错// 折叠-实例化为void f1(int x)f1int(n);f1int(0); // 报错// 折叠-实例化为void f1(const int x)f1const int(n);f1const int(0);// 折叠-实例化为void f1(const int x)f1const int(n);f1const int(0);// 没有折叠-实例化为void f2(int x)f2int(n);// 报错f2int(0);// 折叠-实例化为void f2(int x)f2int(n);f2int(0); // 报错// 折叠-实例化为void f2(int x)f2int(n); // 报错f2int(0);return 0;
}万能模版
// 万能引用,传左值是左值,传右值是右值
// 实践中就可以不用写两个模版了
templateclass T
void Function(T t)
{int a 0;T x a;//x;cout a endl;cout x endl endl;
}const int ,虽然在函数内有左值属性可以修改了但是在此基础上加了const就不能修改了相当于const 左值引用
推导实例化
templateclass T
void Function(T t)
{int a 0;T x a;//x;cout a endl;cout x endl endl;
}int main()
{// 10是右值推导出T为int模板实例化为void Function(int t)Function(10);// 右值int a;// a是左值推导出T为int引用折叠模板实例化为void Function(int t)Function(a);// 左值// std::move(a)是右值推导出T为int模板实例化为void Function(int t)Function(std::move(a));// 右值const int b 8;// a是左值推导出T为const int引⽤折叠模板实例化为void Function(const intt)// 所以Function内部会编译报错x不能Function(b);// const 左值// std::move(b)右值推导出T为const int模板实例化为void Function(const intt)// 所以Function内部会编译报错x不能Function(std::move(b));// const 右值return 0;
}2.8 完美转发 如果t是左值引用的话里面的Fun(t)调用的是左值引用如果t是右值引用调用的还是左值引用因为在函数体内右值具有了左值的属性 templateclass T
void Function(T t)
{Fun(t);//Fun(forwardT(t));
}完美转发可以解决上述的问题 Fun(forward T (t)) 中如果T是int,会保证t还是是左值属性如果T是int会保证t还是右值属性不会让t的属性退化正常的不用完美转发右值引用之后右值会退化成左值属性 底层强转和特化处理的是这样处理的如果是左值属性就不动如果是右值属性就把左值属性强转为右值属性 下面是push_back函数右两个版本的左值走拷贝构造右值走移动构造
2.9 引用折叠和完美转发的实例
引用折叠和完美转发的实际作用 避免了代码的冗余不用写一份右值引用和一份左值引用的了直接写成函数模版就非常好 X data T(),因为类模板实例化出了T为string,如果T是string的左值引用给不过去因为是左值是string,T是右值的话可以给过去右值是string所以要写成 X data,还要写一份强制生成左值和右值的构造