繁体   English   中英

可变参数模板扩展中的函数调用顺序

[英]Order of function calls in variadic template expansion

我在开源项目中找到了基本上看起来像这样的代码:

template< typename... Args >
void expand_calls_hack(Args&&... args)
{}

template <unsigned int... Indices>
struct foo
{
  static void bar(some_tuple_type& t)
  {
    meta::expand_calls_hack((std::get<Indices>(t).doSomething(), 0)...);
  }
};

我认为这个“构造”用于为每个元组元素调用doSomething() 但是,在我看来,调用doSomething()的顺序是未定义的,至少它与C ++ 03中的普通函数一致。 这将是一个错误,因为调用有副作用。 我有两个问题:

  1. 有什么用(tupleElement.doSomething(),0) - 是逗号运算符吗? 我认为它与使用expand_calls_hack扩展调用有关。

  2. 如何解决这个问题,以便从左到右对呼叫进行评估? 请注意,我需要在VC2013上编译。 我已经尝试扩展lambda列表并按顺序调用它,但我无法编译。

我希望我没有遗漏太多的上下文,但是对于好奇的,这段代码的源代码在github这里,第419行

问题的第一部分非常简单: std::get<I>(t).doSomething()可能返回void 因此,您无法直接将此表达式用作expand_calls_hack()的参数。 即使doSomething()返回void使用逗号运算符也会安排参数出现。

调用可变参数函数模板时函数求值的顺序并不特殊,即评估顺序未定义。 然而,事实证明,使用大括号初始化定义为当一个构造器参数的计算顺序(见,例如, 这个问题 )。 也就是说,您可以使用以下内容保证评估顺序:

namespace meta {
    struct order {
        template <typename... T>
        order(T&&...) {}
    };
}
// ...
template <unsigned int... Indices>
struct foo
{
    template <typename T>
    static void bar(T&& t)
    {
        meta::expand_calls_hack((std::get<Indices>(t).doSomething(), 0)...);
        meta::order{(std::get<Indices>(t).doSomething(), 0)...};
    }
};

在上面的函数中,使用expand_calls_hack()可以在我的系统上回溯表达式,而使用order可以前后对它们进行评估。 我认为使用std::initializer_list<int>可以实现类似的效果,这需要不需要可变参数模板:参数都是int s:

namespace meta {
    struct init_order {
        init_order(std::initializer_list<int>) {}
    };
}

它将与meta::order完全相同。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM