【问题标题】:How can a returned object be assignable?返回的对象如何可分配?
【发布时间】:2012-02-08 13:52:38
【问题描述】:

在 Effective C++ 第 3 条中,Scott Meyers 建议为名为 Rational 的类重载 operator*

    class Rational { ... };
    const Rational operator*(const Rational& lhs, const Rational& rhs);

返回值为const-qualified的原因解释如下:如果不是const,程序员可以编写如下代码:

    (a * b) = c;

或者,更有可能:

     if (a*b = c)

很公平。 现在我很困惑,因为我认为函数的返回值(此处为 operator*)是一个右值,因此不可赋值。我认为它不可分配,因为如果我有:

    int foo();
    foo() += 3;

这将无法使用invalid lvalue in assignment 进行编译。 为什么这里不会发生?有人可以对此有所了解吗?

编辑:我在 Scott Meyers 的那个项目上看到了许多其他线程,但没有一个解决我在这里暴露的右值问题。

【问题讨论】:

  • 对于类类型,左值/右值和可分配性是正交的。有些左值是您无法分配的,有些是您可以分配的右值。如果您将左值视为“左侧”而将右值视为“右侧”,请忘记这一点。 C++ 以不同的方式使用术语左值和右值。

标签: c++ constants rvalue


【解决方案1】:

关键是对于类类型,a = b 只是a.operator=(b) 的简写,其中operator= 是一个成员函数。并且可以在右值上调用成员函数。

请注意,在 C++11 中,您可以通过将 operator= 设为仅左值来抑制这种情况:

class Rational
{
public:
  Rational& operator=(Rational const& other) &;
  // ...
};

& 告诉编译器这个函数不能在右值上调用。

【讨论】:

  • 或者换句话说,*运算符返回一个临时对象。就像一个独立的 Rational() 一样,您可以将其用作左值。
  • 此外,至少有一个可分配返回值的合法用例:operator[]。如果你不能提供一个不像数组索引器的重载,那就太奇怪了。
  • @TamásSzelei:operator[] 通常返回一个对对象的引用,它是一个左值,所以这不适用。但是,有时会返回一个代理对象(例如,允许多个索引),在这种情况下,确实需要对右值进行赋值。
  • @MrLister:不,Rational() 不是左值。例如,您不能获取它的地址(好吧,除非您显式重载了地址运算符,在这种情况下,它再次只是一个成员函数调用)。
  • @MrLister:不,你不能void* p = &Rational();而不写你自己的operator&。只需询问您的编译器即可。更重要的是,您不能将它传递给采用非常量左值引用的函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-19
  • 2019-07-07
  • 2020-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多