首页 > 解决方案 > 重载运算符返回什么类型的值(对于用户定义的类型):右值还是左值?

问题描述

我正在阅读 Scott Meyers 的《Effective C++: 55 Specific Ways to Improvement Your Programs and Designs》,他说:

让函数返回一个常量值通常是不合适的,但有时这样做可以在不放弃安全性或效率的情况下减少客户端错误的发生率。例如,考虑 operator* 函数的声明:

class Rational { ... };

const Rational operator*(const Rational& lhs, const Rational& rhs);

根据 Meyers 的说法,这样做可以防止像这样的“暴行”,如果 a、b 是原始类型,这将是非法的:

Rational a, b, c;

...

(a * b) = c;

这让我很困惑,在试图理解为什么上述赋值对于原始类型而不是用户定义类型是非法的时,我遇到了右值和左值

在查看了一些 SO 问题后,我仍然觉得我对右值和左值没有深入的了解,但这是我的基本理解:左值引用内存中的一个位置,因此可以分配给(它可以在双方of = 运算符);但是,不能分配右值,因为它没有引用内存位置(例如,来自函数返回和文字的临时值)

我的问题是:为什么分配给两个数字/对象的乘积对于用户定义的类型是合法的(即使它没有意义)但不是原语?它与返回类型有关吗?重载的 * 运算符返回可分配值还是临时值?

标签: c++rvaluelvalue

解决方案


[expr.call]/14:如果结果类型是左值引用类型或对函数类型的右值引用,则函数调用是左值,如果结果类型是对对象类型的右值引用,则为 xvalue,否则为纯右值。

这是有道理的,因为结果没有“名称”。如果您返回一个引用,则暗示它是对某个“有名称”的某个对象的引用通常但并非总是如此)。

然后是这个:

[expr.ass]/1:赋值运算符 (=) 和复合赋值运算符都从右到左分组。都需要一个可修改的左值作为左操作数;它们的结果是一个引用左操作数的左值。

这就是说赋值需要左侧的左值。到目前为止,一切都很好; 你自己已经介绍过了。

那么非const函数调用结果是如何起作用的呢?

根据特殊规定!

[over.oper]/8:: [..]一些预定义的运算符,例如 +=,在应用于基本类型时要求操作数是左值;这不是操作员功能所必需的。

…并=应用于类类型的对象调用运算符函数

我不能轻易回答“为什么”:从表面上看,在处理类时放宽这个限制是有道理的,而对内置函数的原始(继承)限制似乎总是有点过分(在我看来)但出于兼容性原因必须保留。

但是你有像 Meyers 这样的人指出,现在返回值以有效地“撤消”这种变化变得有用(某种程度上)。const

最终,无论哪种方式,我都不会太努力地找到强有力的理由。


推荐阅读