【问题标题】:Sequencing among a variadic expansion可变参数扩展中的排序
【发布时间】:2012-06-01 15:40:30
【问题描述】:

对于这个非变量示例:

int     Func1();
double  Func2();
void    MyFunc( int, double );

int  main()
{
    MyFunc( Func1(), Func2() );
    //...
}

没有指定是先计算Func1()还是Func2(),只是两者都必须在调用MyFunc()之前完成。

这种排序如何与可变参数的扩展一起工作?

template < typename Func, typename ...Args >
void  MyFunc2( Func &&f, Args&& ...a )
{
    int  b[] = { f( std::forward<Args>(a) )... };
    //...
}

假设f 是一个函数对象,它在第一次调用后会改变其状态。会为a 的每个段按顺序调用f 吗?换句话说,f 会在a 的列表中的第一个项目上调用,然后是第二个项目,第三个等等,而不是随机跳过展开的列表?每个项目之间有我们过去所说的序列点吗?

【问题讨论】:

  • “我们过去称为序列点的东西”是什么意思?
  • 我只知道一点点,但是诸如“xy之间有一个序列点”之类的语句已被替换为“x 在 y 之前排序。"新的完整定义更加精确,并且包括线程调整。

标签: c++ c++11 variadic-templates variadic-functions sequence-points


【解决方案1】:

是的,大括号括起来的初始化列表保证了从左到右的求值顺序,而函数调用则不然。所以MyFunc2 会正确排序。

维基百科的文章涵盖了这一点:https://en.wikipedia.org/wiki/Variadic_templates

每个项目之间是否有我们用来调用序列点的东西?

不,虽然它使用逗号标记,但它不是 逗号运算符。

【讨论】:

  • 有趣。但是,pass 的示例不适用于 GCC-4.7。 pass{std::cout &lt;&lt; args...} 中的表达式在我的机器上从右到左执行。这是 GCC-4.7 中的错误吗?还是维基百科上的描述有误?
  • @nosid 我想我记得听说 GCC 有那个错误。 litb写了那篇文章,他从来没有错(呵呵,下次他上线我会问他)
  • 你是对的。我在 §8.5.4.4(n3290 草案)中找到了它:“[..] 初始化子句 [..] 按照它们出现的顺序进行评估。”和“这个求值顺序保持 [..] - 即使通常对调用的参数没有排序限制。”
  • 我已经知道分隔符不是来自another question of mine的逗号运算符,由@nosid回答。
  • 虽然我的第二个示例使用可变参数扩展进行初始化,但我想知道扩展是否在所有情况下都按顺序排列。环顾四周,这里的答案是正确的,事实并非如此。关于可变参数模板的部分(14.5.3)没有给出排序方向,并指出扩展在同一个地方完全像一个普通的逗号分隔列表。因此,排序规则与正常列表中的任何内容相匹配。 (括号初始化列表在 8.5.4/p4 中排序,函数参数在 8.3.6/p9 中未排序。)
猜你喜欢
  • 1970-01-01
  • 2012-02-29
  • 2013-10-03
  • 1970-01-01
  • 2014-10-30
  • 1970-01-01
相关资源
最近更新 更多