网站建设 团队,友情链接交换工具,深圳营销型网站建设 龙华信科,网站建设 新手从目录
一、类型分类
二、引用折叠
三、完美转发 一、类型分类
C11以后#xff0c;进一步对类型进行了划分#xff0c;右值被划分纯右值(pure value#xff0c;简称prvalue)和将亡值 (expiring value#xff0c;简称xvalue)。
纯右值是指那些字面值常量或求值结果相当于…目录
一、类型分类
二、引用折叠
三、完美转发 一、类型分类
C11以后进一步对类型进行了划分右值被划分纯右值(pure value简称prvalue)和将亡值 (expiring value简称xvalue)。
纯右值是指那些字面值常量或求值结果相当于字面值或是一个不具名的临时对象。如 42、true、nullptr 或者类似str.substr(1, 2)、str1 str2 传值返回函数调用或者整形a、baab 等。纯右值和将亡值C11中提出的C11中的纯右值概念划分等价于C98中的右值。
将亡值是指返回右值引用的函数的调用表达式和转换为右值引用的转换函数的调用表达如 move(x)、static_castX(x)
泛左值(generalized value简称glvalue)泛左值包含将亡值和左值。
二、引用折叠
C中不能直接定义引用的引用如int r i; 这样写会直接报错通过模板或 typedef中的类型操作可以构成引用的引用。
通过模板或 typedef 中的类型操作可以构成引用的引用时这时C11给出了一个引用折叠的规则右值引用的右值引用折叠成右值引用所有其他组合均折叠成左值引用。
下面的程序中很好的展示了模板和typedef时构成引用的引用时的引用折叠规则
像f2这样的函数模板中T x参数看起来是右值引用参数但是由于引用折叠的规则他传递左值时就是左值引用传递右值时就是右值引用有些地方也把这种函数模板的参数叫做万能引用。
Function(T t)函数模板程序中假设实参是int右值模板参数T的推导int实参是int左值模板参数T的推导int再结合引用折叠规则就实现了实参是左值实例化出左值引用版本形参的Function实参是右值实例化出右值引用版本形参的Function。
// 由于引用折叠限定f1实例化以后总是一个左值引用
templateclass T
void f1(T x)
{}
// 由于引用折叠限定f2实例化后可以是左值引用也可以是右值引用
templateclass T
void f2(T x)
{}
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// 没有折叠-实例化为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;
}
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;
} 三、完美转发
Function(T t)函数模板程序中传左值实例化以后是左值引用的Function函数传右值实例化以后是右值引用的Function函数。
结合之前的讲解变量表达式都是左值属性也就意味着一个右值被右值引用绑定后右值引用变量表达式的属性是左值也就是说Function函数中t的属性是左值那么我们把t传递给下一层函数Fun那么匹配的都是左值引用版本的Fun函数。这里我们想要保持t对象的属性就需要使用完美转发实现。
template class T T forward (typename remove_referenceT::typearg);
template class T T forward (typenameremove_referenceT::type arg)
完美转发forward本质是一个函数模板他主要还是通过引用折叠的方式实现下面示例中传递给Function的实参是右值T被推导为int没有折叠forward内部t被强转为右值引用返回传递给Function的实参是左值T被推导为int引用折叠为左值引用forward内部t被强转为左值引用返回。
template class _Ty
_Ty forward(remove_reference_t_Ty _Arg) noexcept
{ // forward an lvalue as either an lvalue or an rvaluereturn static_cast_Ty(_Arg);
}void Fun(int x) { cout 左值引用 endl; }
void Fun(const int x) { cout const 左值引用 endl; }void Fun(int x) { cout 右值引用 endl; }
void Fun(const int x) { cout const 右值引用 endl; }templateclass T
void Function(T t)
{Fun(t);//Fun(forwardT(t));
}
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(b); // const 左值// std::move(b)右值推导出T为const int模板实例化为void Function(const intt)Function(std::move(b)); // const 右值return 0;
} 看一下第二个使用场景 把上一篇文章最后的代码借过来
int main()
{std::listbit::string lt;bit::string s1(111111111111111111111);lt.push_back(s1);cout ************************* endl;lt.push_back(bit::string(22222222222222222222222222222));cout ************************* endl;lt.push_back(3333333333333333333333333333);cout ************************* endl;lt.push_back(move(s1));cout ************************* endl;return 0;
}
//运行结果
string(char* str)
string(const string s) --拷贝构造
* ************************
string(char* str)
string(string s) --移动构造
~string() --析构
* ************************
string(char* str)
string(string s) --移动构造
~string() --析构
* ************************
string(string s) --移动构造
* ************************
~string() --析构
~string() --析构
~string() --析构
~string() --析构
~string() --析构 本篇完下篇继续C11