在等号左边就是左值吗? 临时变量在等号左边,算左值还是右值

C++语言 码拜 8年前 (2016-04-06) 1531次浏览
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

a1+a2构造了一个临时变量,是右值。

5

首先,左值右值针对的是表达式而不是变量或对象
其次,在 C++ 中早就不能通过能否能出现在等号左边来判断能否为左值了,在 C++11 标准出现后除了 glvalue/prvalue 还增加了 xvalue,判定方法更为复杂
参考 https://www.zhihu.com/question/28039779

5

auto& a =  测试的表达式 变量  等等..
能编译过去就是左值.

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

更正,重载的=可以要求*左边*只能是右值不能是左值… oTZ

5

C++17对 value category 有大改。本人个人没理解错的话,在 C++17  ,等号左边的就只能是 glvalue (泛左值)了,特定情况下 prvalue 可以转换为 glvalue

5

终于又能说话了… oTZ
更正,是没有引用修饰的成员函数可以用隐含参数绑定右值。
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]

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明在等号左边就是左值吗? 临时变量在等号左边,算左值还是右值
喜欢 (0)
[1034331897@qq.com]
分享 (0)