如果我写f(x)->g(args, ...)
,我可以在评估f(x)
之前依赖args, ...
之后的序列点吗?我可以通过两种方式看到论点:
this
,好像我写了g(f(x), args, ...)
,这表明它就像一个参数,因此未指定。 ->
运算符不是普通的二元运算符,因为g(...)
无法在f(x)
之前进行评估,就像我写f(x) + g(...)
一样}。我很惊讶我找不到一些具体的说法。
答案 0 :(得分:12)
答案取决于您正在使用的C ++标准版本(或您的编译器正在使用)。
C ++ 2003 5.2.2 p8说:
参数的评估顺序未指定。参数表达式求值的所有副作用在输入函数之前生效。后缀表达式和参数表达式列表的评估顺序未指定。
这意味着在评估f(x)
和args
之间存在不序列点。
在C ++ 2011中,序列点的整个概念已经被替换(参见N1944),而且这个措辞现在只是一个注释:
[注意:后缀表达式和参数表达式的评估都是相对于彼此无法排序的。在输入函数之前,对参数表达式评估的所有副作用进行排序(参见1.9)。 - 结束记录]
和1.9 p15说
当调用函数时(无论函数是否为内联函数),在执行每个表达式或语句之前,对与任何参数表达式或指定被调用函数的后缀表达式相关联的每个值计算和副作用进行排序。被调用函数的主体。 [注意:与不同参数表达式相关的值计算和副作用未被排序。 - 结束记录]
这表示表达式f(x)
和表达式args
在g
正文中的所有内容之前排序,但是它们相对于彼此没有排序,这与C ++ 03规则,但措辞不同。
C ++ 14与C ++ 11具有相同的规则,但正如下面的评论所述,规则在C ++ 17中发生了变化。
C ++ 2017 8.2.2 [expr.call] p5说:
postfix-expression在表达式列表中的每个表达式和任何默认参数之前进行排序。参数的初始化(包括每个相关的值计算和副作用)相对于任何其他参数的初始化是不确定的。
这意味着您的示例将按顺序执行以下步骤:
f
。x
并初始化f
的参数。f(x)
。f(x)->g
。args
和g
的其他参数被评估,g
的参数被初始化(以未指定的顺序)。f(x)->g(args, ...)
。答案 1 :(得分:4)
请注意,我认为您在标题中提出了一个问题,在问题正文中提出了另一个问题。
嗯,这并不是真的矛盾。要评估您的功能,必须执行以下操作(不一定按此顺序)。
现在,您引用的规则表明
但是,未经测试的是(A),(B)和(C)之间的关系,或者(B)和(C)和(D)之间的关系,因为它们不是(() F),之后可以对它们进行评估。或者,他们可以事先进行评估。
*有趣的问题。如果g(args,...)是静态成员函数会发生什么。在这种情况下,由于实际上没有传入来自f(x)的返回指针,它是否可以提前排序?但这是一个单独的问题。