将参数包拆分为0 ... N-1和第N个元素

时间:2014-09-05 12:21:12

标签: c++11 variadic-templates

我想将参数包拆分为第一个N-1和第N个参数,而不使用典型的index_sequence&元组技巧但似乎无法绕过它,但我很确定它应该可行吗? (通过递归获得最后一项很容易)。

调用的最终函数看起来像

void Fun( Foo a, Bar b );

和a依次从可变参数获得:

template< class... T >
Foo CalcFoo( T... args );

我目前的实施:

//get the last item of the pack
template< class T >
T split_last( T t ){ return t; }

template< class... T >
T split_last( T, T... t ){ return split_last( t... ); }

//helper
template< class... T, size_t... Indices >
Foo CalcFoo( const std::tuple< T... >& args, index_sequence< Indices... > )
{
  return CalcFoo( std::get< Indices >( args )... );
}

//split and call
template< class... T >
void MoreFun( T... args )
{
  //make a tuple containing all, then get n -1 items out of it
  const auto tup = std::make_tuple< T... >( args... );
  Fun( CalcFoo( tup, make_index_sequence< sizeof...( T ) - 1 >() ),
       split_last( args... ) ); 
}

更新除了想要知道如何在没有元组的情况下这样做,我也问过这个因为我不知何故认为元组会导致开销。从而忽略了过早优化的口头禅,这通常会再次证明是正确的。使用VS2013在发布模式下编译我和Horstling的代码都会产生完全相同的汇编代码。在调用CalcFoo之前,内容包括Fun在内的所有内容都已内联。换句话说:元组完全消失了。所以我可能会坚持这个实现,因为它非常清楚。

1 个答案:

答案 0 :(得分:4)

好的,让我们有创意。我确信有更“标准”的方法可以做到这一点,但我有点像这个解决方案;)

http://coliru.stacked-crooked.com/a/25a3fa276e56cd94

核心思想是递归地旋转参数,直到我们可以拆分(以前)最后一个参数。

template <size_t N>
struct MoreFunHelper
{
    template <class Head, class... Tail>
    static void RotateLeft(Head head, Tail... tail)
    {
        MoreFunHelper<N - 1>::RotateLeft(tail..., head);
    }
};

template <>
struct MoreFunHelper<0>
{
    template <class Head, class... Tail>
    static void RotateLeft(Head head, Tail... tail)
    {
        Fun(CalcFoo(tail...), head);
    }
};

template< class... T >
void MoreFun(T... args)
{
    MoreFunHelper<sizeof...(T) - 1>::RotateLeft(args...);
}

所以如果我们从参数开始

1 2 3 4 5

它将它们旋转4次:

2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4

现在我们可以顺利地将它们分成[5]和[1 2 3 4],这正是我们想要的。此时,递归停止,只调用函数CalcFooFun