a && b && c 由语言定义的意思 (a && b) && c 或者 a && (b && c)?

哇,杰瑞速度真快。为了加强这个问题:这真的重要吗?之间是否存在可观察到的差异 a && b && c 被解释为 (a && b) && c 或者 a && (b && c)?

有帮助吗?

解决方案

§5.14/1:“&& 运算符从左到右分组。...]与&&&保证从左到右评估:如果第一个操作数为 false,则不会计算第二个操作数。”

至于何时或如何重要:我不确定它是否真的适用于内置类型。然而,有可能以某种方式使其超载,从而使其变得重要。例如:

#include <iostream>

class A;

class M {
    int x;
public:
    M(int x) : x(x) {}
    M &operator&&(M const &r); 
    M &operator&&(A const &r); 
    friend class A;
};

class A {
    int x;
    public:
    A(int x) : x(x) {}
    A &operator&&(M const &r); 
    A &operator&&(A const &r);
    operator int() { return x;}
    friend class M;
};

M & M::operator&&(M const &r) {
    x *= r.x;
    return *this;
}

M & M::operator&&(A const &r) {
    x *= r.x;
    return *this;
}

A &A::operator&&(M const &r) {
    x += r.x;
    return *this;
}

A &A::operator&&(A const &r) {
    x += r.x;
    return *this;
}

int main() {
    A a(2), b(3);
    M c(4);

    std::cout << ((a && b) && c) << "\n";
    std::cout << (a && (b && c)) << "\n";
}

结果:

9
16

警告:这仅表明它是如何 变得重要。我是 不是 特别建议任何人这样做,只是表明,如果你足够渴望,你可以创造一种能够产生影响的情况。

其他提示

&&|| 操作员短路:如果左侧的操作数决定了整个表达式的结果,则右侧的操作数甚至不会被计算。

因此,数学家会将它们描述为左结合的,例如
a && b && c(a && b) && c, ,因为对于数学家来说这意味着 ab 被首先考虑。不过,出于教学目的,写一下可能会有用 a && (b && c) 相反,要强调的是 两者都不 b 也不 c 将被评估,如果 a 是假的。

C 中的括号仅在覆盖时更改计算顺序 优先级. 。两个都 a && (b && c)
(a && b) && c 将被评估为 a 首先,然后 b, , 然后 c. 。同样,两者的评估顺序
a + (b + c)(a + b) + c 未指定。对比 a + (b * c) 相对 (a + b) * c, ,编译器仍然可以自由地评估 a, b, , 和 c 顺序任意,但括号决定先进行乘法还是先加法。还要对比 FORTRAN,其中至少在某些情况下必须首先计算括号表达式。

事实上,表达式从左到右计算是非常重要的。这在某些表达式中用于短路。这是一个确实很重要的案例:

vector<vector<int> > a;
if (!a.empty()  && !a[0].empty() && a[0].back() == 3) 

我敢打赌你每天都会写几次类似的陈述。如果未定义关联性,您将遇到巨大的麻烦。

如果 a && b 是假的,那么 && c 部分从未经过测试。所以是的,这确实很重要(至少因为您需要从左到右对操作进行排序)。 && 本质上是一种结合运算。

关联属性

在同一关联操作员的一排中包含两个或多个出现的表达式中,只要操作数的序列不更改,执行操作的顺序就无关紧要。也就是说,在这种表达式中重新排列括号不会改变其值。

所以如果你把它写成(从逻辑上来说)并不重要 a && (b && c) 或者 (a && b) && c. 。两者是等价的。但你不能改变操作的顺序(例如 a && c && b 不等于 a && b && c).

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top