在折叠表达式中使用后增量会产生无序行为吗?

Ran*_*nza -1 c++ gcc clang fold-expression

最近我想出了一个想法,如何枚举参数包(脉冲)中的元素,我对这个解决方案很满意一段时间:

lastValue = 0.0; i = -1;
lastValue += (... + ((time <= endtimes[++i] && time >= delays[i]) ? static_cast<Pulses*>(fields[i])->operator()(time - delays[i]) : 0.0));
Run Code Online (Sandbox Code Playgroud)

但是现在当我尝试使用 Clang 而不是 GCC 进行编译时,我收到了以下警告

警告:对“i”的多次未排序修改 [-Wunsequenced]

我读过几篇关于无序修改的帖子,但在他们的例子中,修改要么在表达式中发生两次,要么发生在“=”运算符的左侧。

另一方面,我的理解是参数包是按顺序评估的,所以......没有未排序的行为,对吗?或者我在这里完全错了,编译器总是对的?

Hol*_*Cat 5

Clang 是对的,代码导致 UB。

折叠表达式的计算规则与普通表达式完全相同。

的两个操作数的评价+(以及大多数二元运算)是未测序相对于彼此(即可以以任何顺序发生,可能是交错的),并导致UB标量变量的未测序的改变。

解决方案很简单:使用运算符,进行折叠,而不是+. 对于,,第一个操作数在第二个操作数之前完全评估,因此有一个明确的评估顺序并且没有 UB。

lastValue = 0.0; i = -1;
((lastValue += ((time <= endtimes[++i] && time >= delays[i]) ? static_cast<Pulses*>(fields[i])->operator()(time - delays[i]) : 0.0)), ...);
Run Code Online (Sandbox Code Playgroud)

或者,使用 lambda 使其不那么难看:

lastValue = 0.0; i = 0;
([&]{
    if (time <= endtimes[i] && time >= delays[i])
        lastValue += static_cast<Pulses*>(fields[i])->operator()(time - delays[i]);
    i++;
}(), ...);
Run Code Online (Sandbox Code Playgroud)