【问题标题】:Evaluation order of overloaded operator |?重载运算符的求值顺序 |?
【发布时间】:2011-11-03 09:14:01
【问题描述】:

5.15 标准中的逻辑或运算符表示如下:

不像 |, ||保证从左到右的评估;

这是否意味着我无法在标准中找到某个地方,| 被定义为从右到左评估,或者它是实现定义的?当运算符重载时,这会有所不同吗?我编写了一个快速程序来测试这一点,MSVC++ 和 GCC 似乎都在评估 从右到左

#include<iostream>
using namespace std;

int foo = 7;

class Bar {
public:
    Bar& operator|(Bar& other) {
        return *this;
    }
    Bar& operator++() {
        foo += 2;
        return *this;
    }
    Bar& operator--() {
        foo *= 2;
        return *this;
    }
};

int main(int argc, char** argv) {
    Bar a;
    Bar b;
    Bar c = ++a | --b;
    cout << foo;
}

这会输出16。 如果++a--b 切换,则输出19

我还考虑过我可能会遇到序列点规则之间的多次更改(以及因此未定义的行为),但我不确定这如何/是否适用于两个单独的实例作为操作数。

【问题讨论】:

  • 请注意,尽管 ab 是不同的实例,但它们都引用相同的 foo,因此您确实在调用未定义的行为,因为您多次写入同一个变量而没有一个中间序列点。
  • 调用每个算子都是一个序列点,这样就可以了。

标签: c++ operators undefined standards-compliance operator-precedence


【解决方案1】:

暂时忽略那个操作符,注意这一点:

(x + y) * (z + 1)

这里,两个操作数都必须在乘法发生之前求值(否则我们不知道要乘什么)。在 C++ 中,执行此操作的顺序是未指定:它可以是 (x + y) 首先,或者 (z + 1) 首先,无论编译器感觉更好。†

运算符| 也是如此。但是,运算符|| 必须短路,并且为了做到这一点,它必须严格从左到右进行评估。 (如果左边的计算结果是true,那么计算结束而不计算右边的操作数。)这就是句子的意思。

†请注意,它可能没有任何偏好,只需按照列出的顺序进行评估。这就是为什么你会得到你所做的输出,尽管你不能在语言级别依赖它。

【讨论】:

  • 如果左操作数为真,是否应该结束评估?
【解决方案2】:

正如其他人所说,这意味着双方的评估顺序未指定。回答您的其他问题 -

我还考虑过我可能会遇到序列点规则之间的多次更改(以及因此未定义的行为)

不,您的案例不会修改两个相邻序列点之间的foo。在进入函数之前和离开函数之前,总是有一个序列点,这意味着foo的两次修改都发生在两对不同的序列点之间。

当运算符重载时,这会有所不同吗?

第 5 条中的所有内容都只讨论了内置运算符。对于用户定义的运算符实现,这些规则不适用。同样对于||,对于用户定义的运算符,没有指定顺序。但请注意,它仅适用于用户定义的运算符;不是当两个操作数都转换为 bool 并触发内置运算符时:

struct A { 
  operator bool() const { return false; }
};

struct B {
  operator bool() const { return true; }
};

int main() {
  A a;
  B b;
  a || b;

  shared_ptr<myclass> p = ...;
  if(p && p->dosomething()) ...;
}

这将始终首先执行A::operator bool,然后执行B::operator bool。如果p 的计算结果为true,它只会调用p-&gt;dosomething()

【讨论】:

  • ||&amp;&amp; 的奇怪处理方式几乎不会使它们超载,因为我能想到的几乎所有此类情况都会令人困惑。关于我能想到的唯一情况是,如果您将它们用于完全陌生的目的,例如 BNF 语法的 C++ 表示法或其他东西。
【解决方案3】:

这是否意味着我无法在标准中找到某个地方,|被定义为从右到左评估,还是它是实现定义的?

从迂腐的角度来说,| 运算符的参数评估顺序是未指定的。所以这意味着操作数可以按任意顺序计算。

但是,指定了逻辑运算符(即&amp;&amp;|| 等)和逗号运算符的操作数的计算顺序,即从左到右。

【讨论】:

  • 除非,如果&amp;&amp;|| 过载,我认为这不适用。
猜你喜欢
  • 2018-03-06
  • 2010-11-29
  • 2021-08-23
  • 2021-07-12
  • 2014-12-11
  • 1970-01-01
  • 2023-04-03
  • 2020-08-15
  • 1970-01-01
相关资源
最近更新 更多