C++中prvalue为何可作为赋值运算符的左操作数?
C++中prvalue作为赋值左操作数的疑问
我在cppreference的值类别页面中发现一个示例存在特殊语法:
#include <iostream> struct S { S() : m{42} {} S(int a) : m{a} {} int m; }; int main() { S s; // Expression `S{}` is prvalue // May appear on the right-hand side of an assignment expression s = S{}; std::cout << s.m << '\n'; // Expression `S{}` is prvalue // Can be used on the left-hand side too std::cout << (S{} = S{7}).m << '\n'; }
其中main()最后一行的S{} = S{7}将prvalue作为赋值运算符左操作数。我简化后的代码如下:
#include <iostream> struct S { int m = 1; }; int main() { std::cout << (S{} = S{}).m << '\n'; }
该代码编译无警告或错误,但该页面文档指出:
An rvalue can't be used as the left-hand operand of the built-in assignment or compound assignment operators.
S{}是prvalue,属于rvalue范畴,为何C++允许此操作?它是如何将prvalue转换为lvalue的?
解答
核心原因是内置赋值运算符和类类型的自定义赋值运算符的规则差异:
- 文档里提到的「右值不能作为内置赋值运算符的左操作数」,针对的是
int、float这类内置基本类型的赋值(比如1 = 2这种写法肯定报错)。 - 而你代码中的
S{} = S{7},调用的是结构体S的默认生成的赋值运算符成员函数(本质是用户自定义的成员函数),不是内置赋值运算符。
对于类类型的成员函数,不管表达式是左值还是右值,都可以调用其非const成员函数——包括赋值运算符。具体过程是:
- 首先创建临时的prvalue对象
S{}; - 对这个临时对象调用赋值运算符
operator=,此时prvalue会被绑定到成员函数的隐式this指针上。对于非const成员函数,this指针指向的是左值类型(因为成员函数默认允许修改对象,哪怕它是临时的); - 赋值运算符返回的是
*this,也就是该临时对象的左值引用,因此后续可以通过.m访问其成员。
简单总结:临时prvalue对象可以调用自己的赋值成员函数,这是C++针对类类型的合法规则,和内置类型的赋值规则不冲突。
内容的提问来源于stack exchange,提问作者Maxim Fomin
相关产品推荐
相关产品推荐

