C ++ 11:参数包扩展计数器

时间:2016-06-06 22:44:53

标签: c++ templates c++11 parameter-passing

我想在参数包扩展期间为每个参数增加一个计数器。 这是我想要实现的一些伪代码:

    template<class ... Args>
    void doSomething(Args ... _args)
    {
        std::size_t counter = 0;
        bar(doSomethingWithOneArg(_args, counter++)...);
    }

此代码的问题在于,虽然保留了Args的顺序,但未定义评估函数参数的顺序,即在clang上计数器的顺序表达式的评估与Args的顺序相同,而gcc中的表达式则相反。实现这一目标的便携式标准方法是什么?

谢谢!

3 个答案:

答案 0 :(得分:4)

您可以添加辅助功能:

<svg>
<path fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" d="M21,34.328C21,15.693,32.477,0.515,50.124,0.515
    C67.77,0.515,79,16.928,79,34.328c0,17.399-29,65.157-29,65.157S21,52.962,21,34.328z"/>
</svg>

答案 1 :(得分:1)

如果您希望评估顺序与doSomething的参数顺序一致,您可以将参数扩展为初始值设定项:

template <typename ...Args, std::size_t ...N>
void doSomethingImpl(std::index_sequence<N...>, 
  std::tuple<Args...> && args)
{
  using std::get;
  int t_[] = { 0, (static_cast<void>(oneCommand(
    get<N>(std::forward<decltype(args)>(args)), N)), 0)... };
  static_cast<void>(t_); // "use" t_ to silence warnings 
}

template <typename ...Args>
void doSomething(Args &&... args)
{
  doSomethingImpl(std::make_index_sequence<sizeof...(Args)>(),
    std::forward_as_tuple(std::forward<Args>(args)...));
}

答案 2 :(得分:1)

您可以将list-initializatio与逗号运算符结合使用来对函数调用进行排序:

template<class T>
void doSomethingWithOneArg(const T&, std::size_t counter)
{
    std::cout << counter << ": " << typeid(T).name() << '\n';
}

template<class ... Args>
void doSomething(Args ... args)
{
    std::size_t counter = 0;
    std::initializer_list<int>{ ( doSomethingWithOneArg(args, counter++), 0) ... };
}

int main() {
    doSomething(char(0), int(0), long(0));
}

8.5.4列表初始化(N4296)

  

4   在braced-init-list的initializer-list中,   initializer-clause,包括包扩展产生的任何条款   (14.5.3),按照它们出现的顺序进行评估。那是,   与给定相关的每个值计算和副作用   initializer-clause在每个值计算之前排序   与其后面的任何初始化子句相关联的副作用   逗号分隔的初始化列表列表。