调用参数置换不变函数f(i ++,i ++)

时间:2018-09-20 17:47:18

标签: c++ c++17

假设我有一个不变的函数foo(x, y, z)。其参数的所有排列。我还拥有一个迭代器it,因此可以取消引用迭代器itit + 1it + 2

写好吗

... = foo(*it++, *it++, *it++);  // (1)

代替

... = foo(*it, *(it + 1), *(it + 2));  // (2)

据我所知,从技术上讲,这是正确的,因为C ++ 17是由于(引用cppreference.com并考虑到it可能是原始指针)

  

15)在函数调用中,相对于任何其他参数的值计算和副作用,每个参数初始化的值计算和副作用都不确定地排序。

函数参数的求值顺序未定义,但是对于foo()而言,顺序无关紧要。

但这是可接受的编码样式吗?一方面,(1)具有很好的对称性,并暗示foo具有这样的不变性,而(2)看起来有些丑陋。另一方面,(1)立即提出有关其正确性的问题-读取代码的人应检查foo的描述或定义以验证呼叫的正确性。

如果foo()的主体很小,并且从函数定义中可以明显看出不变性,您会接受(1)吗?

(这个问题可能是基于观点的。但是我不禁要问。)

1 个答案:

答案 0 :(得分:6)

您是正确的,在C ++ 17中

foo(*it++, *it++, *it++);

不是未定义的行为。如您的报价所述,并按[expr.call]/8

中所述
  

postfix-expression在expression-list中的每个表达式和任何默认参数之前进行排序。参数的初始化(包括每个相关的值计算和副作用)相对于任何其他参数的不确定地排序。

每个增量都是有序的,因此您不会有多个未排序的写操作。在C ++ 17中,函数参数的求值顺序仍未指定,这意味着您只是具有未指定的行为(您不知道将哪个元素传递给每个参数)。

只要您的函数对此不关心,就可以了。如果参数的顺序很重要,则必须使用第二个版本。


所有人都说我更喜欢使用

foo(*it, *(it + 1), *(it + 2));

即使顺序无关紧要。它使代码向后兼容,恕我直言,因此更容易推理。我宁愿在for循环的增量部分中看到一个it += 3,然后在函数调用中看到多个增量,而在循环的增量部分中看到没有增量。