我正在阅读Scott Meyers撰写的有效的C ++:55种改善程序和设计的特定方法,他说:
让一个函数返回一个常量值通常是不合适的,但是有时候这样做可以减少客户端错误的发生而又不放弃安全性或效率。例如,考虑operator *函数的声明:
class Rational { ... };
const Rational operator*(const Rational& lhs, const Rational& rhs);
根据迈耶斯的说法,这样做可以防止这样的“暴行”,如果a,b是原始类型,这将是非法的:
Rational a, b, c;
...
(a * b) = c;
这让我感到困惑,在试图理解为什么上述赋值对于原始类型而不是用户定义类型是非法的时,我遇到了rvalues和lvalues
在研究了一些SO问题之后,我仍然觉得我对rvalues和lvalues的含义并不十分了解,但这是我的基本理解:lvalue引用内存中的位置,因此可以分配给它(可以同样在=运算符的两侧);但是,不能将一个右值分配给它,因为它不引用内存位置(例如,函数返回值和文字中的临时值)
我的问题是:为什么将分配给两个数字/对象的乘积合法用于用户定义的类型(即使这没有意义)却不符合原语?它与返回类型有关吗?重载的*运算符会返回可分配值还是临时值?
答案 0 :(得分:3)
[expr.call]/14:
如果结果类型是左值引用类型或对函数类型的右值引用,则函数调用为左值,如果结果类型是对对象类型的右值引用,则函数调用为xvalue,否则为prvalue。
这很有意义,因为结果没有“具有名称”。如果返回引用,则表示该引用是对某个有“具有名称”的对象的引用(通常但并非总是如此)。
然后是这个
[expr.ass]/1:
赋值运算符(=)和复合赋值运算符均从右到左分组。它们都需要可修改的左值作为其左操作数;它们的结果是一个指向左操作数的左值。
这就是说,赋值要求左侧有一个左值。到目前为止,一切都很好;您已经自己解决了这个问题。
那么非const
函数调用结果如何工作?
按照特殊规则!
[over.oper]/8:
: [..] 一些预定义的运算符(例如+ =)在应用于基本类型时要求操作数为左值。操作员功能不需要这样做。
…和=
应用于类类型的对象会调用操作符 function 。
我不能轻易回答“为什么”:从表面上看,在处理类时放宽此限制是有意义的,并且内置的原始(继承)限制似乎总是有点过分(在我的看法),但出于兼容性原因必须保留。
但是随后,像Meyers一样的人指出,现在返回const
值以有效地“撤消”此更改成为有用的(某种)。
最终,我不会为找到一种可靠的理由而努力。