在下面的代码片段中,为什么行2 + 3 = 5
语句给出错误,但是分配给字符串连接的下一条语句成功编译?
#include <string>
int main() {
2 + 3 = 5; // Error: lvalue required as left operand of assignment
std::string("2") + std::string("3") = std::string("5"); // Compiles successfully. why?
return 0;
}
我的理解是,表达式std::string("2") + std::string("3") = std::string("5")
的左侧将产生临时值rvalue
。这意味着我正在分配给rvalue
-就像2 + 3 = 5
。因此,它也应该给出lvalue required as left operand of assignment
错误。但事实并非如此。
对于类类型,分配是通过复制和移动分配运算符实现的。 std::string
是一门课程,所以
std::string("2") + std::string("3") = std::string("5")
仅仅是语法糖
(std::string("2") + std::string("3")).operator=(std::string("5"))
operator=
是成员函数。通常,可以在左值和右值上调用成员函数。因此,此表达式有效。
对于未超载的operator=
(即,对于int
):[expr.ass]/1
[赋值运算符(
=
)和复合赋值运算符所有组从右到左。全部要求可修改的左值左操作数,并返回引用左操作数的左值。[...]
对于过载operator=
(对于std::string
):[expr.ass]/4
如果左操作数是类类型,则该类应是完整的。由复制/移动赋值运算符定义对类对象的赋值([class.copy],[over.ass])。
(所有人都强调我的意思)
该规则仅适用于内置类型的对象,例如int
。
不适用于课程。
[该规则可能被认为对类来说过于严格,其运算符可以被重载以执行各种操作……或者也许在C ++出现时就被认为过于严格,但是通过这种方式破坏旧的C代码并不是很好的做法。也放宽了内置规则。
无论如何,加法的结果实际上是一个左值,因为这是从函数返回一个左值引用(如std::string&
)时得到的。尽管事实是加法的两个操作数都是右值表达式和临时对象。在这种情况下,there's a proposal to do better at "propagating value category"可能有点令人惊讶,因为这种语言为我们提供了执行此操作的工具。