int a=1;//这个a是左值无疑吗?
int a; a=1; int *b; *b=a;//这个*b是左值吗?
问题,本人可以构造一个临时变量,让它出现在等号的左边,如下:
#include<iostream> using namespace std; struct A{ int m_i; A(int i):m_i(i){} A& operator=(int i){ m_i=i; return *this; } A operator+(const A&other){ return A(m_i+other.m_i); } ~A(){cout<<m_i<<endl;} }; int main() { A a1(2); A a2(3); (a1+a2)=5;//这里的(a1+a2)是左值还是右值? return 0; }
上面的main函数中,a1+a2构造了一个临时变量,它出现在等号左边。那么它到底算左值还是右值,还是别的?
5
5
其次,在 C++ 中早就不能通过能否能出现在等号左边来判断能否为左值了,在 C++11 标准出现后除了 glvalue/prvalue 还增加了 xvalue,判定方法更为复杂
参考 https://www.zhihu.com/question/28039779
5
能编译过去就是左值.
5
int a=1;//这个a是左值无疑吗?
这是一个变量定义,即初始化。它不是一个表达式,其中的 a 也不是表达式。所以无所谓左值、右值(左值、右值是表达式的属性)
*b=a;//这个*b是左值吗?
*b 是左值。(*b 是一个表达式,它是 *b=a 的子表达式)
这里的 = 是一个普通的赋值运算符。赋值运算符左侧必须是一个可修改的左值。
(a1+a2)=5;
(a1+a2) 是一个右值。
但这里的 = 不是一个普通的复制运算符。它是一个函数调用,因而对左值、右值的需求按函数调用处理,不服从赋值运算符的规则。
上式实际是:
(a1+a2).operator=(5)
对于成员函数调用,只要调用的对象(这里是 a1+a2 )可以绑定到一个虚拟的增加的参数 A& 上(注1: 注意这个增加的参数不是 this ,类型也与 this 类型不一致;注2: 可以通过在函数声明的参数表后增加 const ,将 func()const ,将这个增加的参数的类型改为 const A& ),就可以成功调用。
在成员函数调用时,增加的这个虚拟的 A& 的参数可以绑定到一个右值上(与通常的引用:
int a=1;//这个a是左值无疑吗?这是一个变量定义,即初始化。它不是一个表达式,其中的 a 也不是表达式。所以无所谓左值、右值(左值、右值是表达式的属性)
*b=a;//这个*b是左值吗?*b 是左值。(*b 是一个表达式,它是 *b=a 的子表达式)
这里的 = 是一个普通的赋值运算符。赋值运算符左侧必须是一个可修改的左值。(a1+a2)=5;(a1+a2) 是一个右值。
但这里的 = 不是一个普通的复制运算符。它是一个函数调用,因而对左值、右值的需求按函数调用处理,不服从赋值运算符的规则。
上式实际是:(a1+a2).operator=(5)对于成员函数调用,只要调用的对象(这里是 a1+a2 )可以绑定到一个虚拟的增加的参数 A& 上(注1: 注意这个增加的参数不是 this ,类型也与 this 类型不一致;注2: 可以通过在函数声明的参数表后增加 const ,将 func()const ,将这个增加的参数的类型改为 const A& ),就可以成功调用。
在成员函数调用时,增加的这个虚拟的 A& 的参数可以绑定到一个右值上(与通常的引用绑定规则不同)
这样, (a1 + a2) 可以绑定到 A& 上,因而函数调用是可以成功的。
[注,这个虚拟的增加的参数并不真实存在,只用于重载判决(overload resolution),即判断函数能否可被调用]int i=3, j =2; (i+j) = 6; // error这里 (i+j) 是一个右值,赋值运算符是一个普通的复制运算符。由于赋值运算符需要左侧是一个可修改的左值,因而是不可以的。
他这里a1 + a2是绑给右值引用了。
#include<iostream> using namespace std; struct A { int m_i; A(int i) :m_i(i) {} A& operator=(int i) && = delete; A& operator=(int i) &{ m_i = i; return *this; } A operator+(const A&other) { return A(m_i + other.m_i); } ~A() { cout << m_i << endl; } }; int main() { A a1(2); A a2(3); (a1 + a2) = 5; // 把右值引用版本的operator=删了就不行了 return 0; }
具体懒得查了,大体上可以看成默认情况下那个隐藏参数是右值引用的,所以可以把prvalue传进去,而在函数内部就可以通过lvalue操作临时对象了。
5
5
5
更正,是没有引用修饰的成员函数可以用隐含参数绑定右值。
For non-static member functions declared without a ref-qualifier, an additional rule applies: —(5.3) even if the implicit object parameter is not const-qualified, an rvalue can be bound to the parameter as long as in all other respects the argument can be converted to the type of the implicit object parameter. [Note: The fact that such an argument is an rvalue does not affect the ranking of implicit conversion sequences (13.3.3.2). —end note]