带括号表达式的用法逗号运算符示例

时间:2019-01-20 13:41:19

标签: c++

res + =(f(i),f(i + 1)),f(i + 2)是什么?评估为?

#include <iostream>
int f(int x)
{
    static int cnt = 0;
    return ++cnt * x;
}
int main ()
{
    int res = 0;
    for (int i = 0; i < 6; ++i) {
        res += (f(i), f(i + 1)), f(i + 2);
//        f(i);
//        res += f(i + 1);
//        f(i + 2);
        std::cout << res << std::endl;
    }
    std::cout << res;
}

我不知道这行是如何工作的:

res += (f(i), f(i + 1)), f(i + 2);

我知道它等同于被注释的部分,但是为什么呢?

1 个答案:

答案 0 :(得分:6)

此答案说明了您使用此表达式观察到的行为:

res += (f(i), f(i + 1)), f(i + 2);

...但是我建议您不要在任何生产代码中使用此代码,出于某些原因,请参阅答案的结尾。


在表达式中使用时,逗号,对应于标准操作符comma operator

// Evaluate E1 then E2, discards the result of E1, return E2
E1, E2

+=运算符也是一个运算符,其优先级比,,的优先级在C ++中最低),因此:

int f();
int g();

int x = 0;

// Equivalent to:
//   x += f(); 
//   g(); 
x += f(), g();

// Equivalent to:
//   f();
//   x += g();
x += (f(), g());

在您的情况下,您需要用一对圆括号括住前两个调用:

res += (f(i), f(i + 1)), f(i + 2);
//     ^--------------^

所以:

  1. f(i), f(i + 1)被评估(由于括号),这导致调用f(i) 然后 f(i + 1),并存储f(i + 1)的结果在临时;
  2. 临时通过res运算符添加到+=
  3. res += (f(i), f(i + 1))的结果将被丢弃;
  4. f(i + 2)被评估。

如注释中所指定,此代码等效于:

f(i);
res += f(i + 1);
f(i + 2);

编译器无法删除对f(i)f(i + 1)的调用,因为它们具有副作用(static变量cnt的更新)。


我建议不要出于此类原因而使用逗号运算符,主要是出于清楚的原因:

  • 与三行版本相比,您不会从中获得任何收益,只是单线的行为不是很明显(这个问题是一个很好的例子……)。
  • 由于逗号运算符对非内置类型的工作方式,直到非内置类型的C ++ 17为止,行为都是不同的。例如,如果f返回一个类似big_int的类,则不能保证operator,的操作数的求值顺序。

从C ++ 17开始,您会获得fold expressions的逗号运算符,这是使用逗号运算符的很少原因之一。