左值右值是表达式的属性,该属性称为 value category。按该属性分类,每一个表达式属于下列之一:
lvalue | left value,传统意义上的左值 |
xvalue | expiring value, x值,指通过“右值引用”产生的对象 |
prvalue | pure rvalue,纯右值,传统意义上的右值(?) |
而 xvalue 和其他两个类型分别复合,构成:
lvalue + xvalue = glvalue | general lvalue,泛左值 |
xvalue + prvalue = rvalue | 右值 |
++x 与 x++ 假定x的定义为 int x=0;,那么前者是 lvalue,后者是rvalue。前者修改自身值,并返回自身;后者先创建一个临时对像,为其赋值,而后修改x的值,最后返回临时对像。
区分表达式的左右值属性有一个简便方法:若可对表达式用 & 符取址,则为左值,否则为右值。比如
&obj , &*ptr , &ptr[index] , &++x | 有效 |
&1729 , &(x + y) , &std::string("meow"), &x++ | 无效 |
对于函数调用,根绝返回值类型不同,可以是lvalue、xvalue、prvalue:
The result of calling a function whose return type is an lvalue reference is an lvalue
The result of calling a function whose return type is an rvalue reference is an xvalue.
The result of calling a function whose return type is not a reference is a prvalue.
左值和右值表达式都可以是const或non-const。
比如,变量和函数的定义为:
string one("lvalue"); const string two("clvalue"); string three() { return "rvalue"; } const string four() { return "crvalue"; }
那么表达式:
表达式 | 分类 |
one | modifiable lvalue |
two | const lvalue |
three() | modifiable rvalue |
four() | const rvalue |
引用
Type& | 只能绑定到可修改的左值表达式 |
const Type& | 可以绑定到任何表达式 |
Type&& | 可绑定到可修改的左值或右值表达式 |
const Type&& | 可以绑定到任何表达式 |
#include <iostream> #include <string> using namespace std; string one("lvalue"); const string two("clvalue"); string three() { return "rvalue"; } const string four() { return "crvalue"; } void func(string& s) { cout << "func(string& s): " << s << endl; } void func(const string& s) { cout << "func(const string& s): " << s << endl; } void func(string&& s) { cout << "func(string&& s): " << s << endl; } void func(const string&& s) { cout << "func(const string&& s): " << s << endl; } int main() { func(one); func(two); func(three()); func(four()); return 0; }
结果:
func(string& s): lvalue func(const string& s): clvalue func(string&& s): rvalue func(const string&& s): crvalue
如果只保留const string& 和 string&& 两个重载函数,结果为:
func(const string& s): lval
lz你好,右值引用当中:
int main() { int && a=1; F2(a); F1(a); F2(2); F1(2); return 0; }
F2(a)会出现编译错误,因为具名右值引用传参时会作为左值,而F2中的参数int &&a 只能绑定非常量右值,而不能绑定左值。
还有你说“对函数的右值引用无论具名与否都将被视为左值”,经过试验只有具名函数的右值引用才会作为左值,而非具名则会作为右值.
试验代码:
#include<iostream>
#include<algorithm>
using std::cout;
using std::endl;
void F1(int &a)
{
cout<<"左值引用"<<endl;
}
void F1(int && a)
{
cout<<"右值引用"<<endl;
}
int test()
{
return 1;
}
int main()
{
int &&a = test();//具名函数右值引用
F1(a);//非常量左值引用只能绑定非常量左值,所以具名函数右值引用会作为左值调用F1(int &a)
F1(test());//非常量右值引用只能1绑定非常量右值,所以非具名函数作为右值调用F1(int &&a)
return 0;
}
模板参数类型当中:
template <typename Type> void Swap(Type&& sb1, Type&& sb2) { Type sb(sb1); sb1 = sb2; sb2 = sb; }sb1和sb都是非常量右值引用,他们是不能绑定作为左值的具名右值引用的。
参见博客:http://www.cnblogs.com/hujian/archive/2012/02/13/2348621.html
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。