C ++:转发参数包和std :: tuple /数组的总和

时间:2014-04-12 01:45:30

标签: c++ c++11 variadic-templates template-meta-programming forwarding

我想实现类似下面的成员函数(方法),它应该通过对应于参数 index 的某个summand(addend)增加每个参数将它转发到另一个variadic-template函数:

template<typename... Int> // a bunch of integral types (e.g. int, size_t, char)
void ForwardToFuncIncreased(Int... ints) {
   static_assert(sizeof...(Ints) == std::tuple_size<decltype(summands_)>::value,
                 "Incorrect number of integral types provided");

   Func( (ints + std::get<PARAM_INDEX(ints)>(summands_))... ); // failed attempt
}

其中summands_std::tuplestd::array类型的成员变量(您可以假设)。基本要求是:与

相比,它应该没有运行时开销
Func(int0 + std::get<0>(summands_), int1 + std::get<1>(summands_), ...);

(想象一下,我为最多N模板参数重载函数。)

如果没有必要的运行时开销就无法做到这一点,我愿意进行某些修改(特别是在我的类中存储其他内容或修改类型的方式)。

注意:我的目的不是提取模板参数索引,而是希望在没有它的情况下实现我的需要。

1 个答案:

答案 0 :(得分:2)

在C ++ 14中,您将能够执行以下操作,与您原来的尝试非常相似:

template<typename... Ns, size_t... Is>
void ForwardToFuncIncreasedImpl(Ns... nums, std::index_sequence<Is...>)
{
    Func( (nums + std::get<Is>(summands_))... );
}

template<typename... Ns>
void ForwardToFuncIncreased(Ns... nums)
{
    ForwardToFuncIncreasedImpl(nums..., std::index_sequence_for<Ns...>());
}

与此同时,您可以找到或编写自己的index_sequence实现。

或者执行以下操作:首先执行std::make_tuple(ints...),以便我们有两个我们想要求和的元组(或者一个元组和一个std::array)。然后使用Andrei Alexandrescu在The Way of the Exploding Tuple中演示的模式将总和扩展为传递给Func的参数包。

template <int N>
struct Pairwise;

template <>
struct Pairwise<0>
{
    template <typename F, typename T, typename U, typename... Args>
    static void Sum(F f, T const&, U const&, Args... sums)
    {
        f(sums...);
    }
};

template <int N>
struct Pairwise
{
    template <typename F, typename T, typename U, typename... Args>
    static void Sum(F f, T const& a, U const& b, Args... sums)
    {
        Pairwise<N - 1>::Sum(f, a, b, std::get<N - 1>(a) + std::get<N - 1>(b), sums...);
    }
};

template <typename... Ns>
void ForwardToFuncIncreased(Ns... nums)
{
    Pairwise<sizeof...(Ns)>::Sum(Func, std::make_tuple(nums...), summands_);
}

在没有初始make_tuple

的情况下,也可以这样做
template <typename... Ns>
struct Pairwise;

template <>
struct Pairwise<>
{
    template <typename F, typename T, typename... Args>
    static void Sum(F f, T const&, Args... sums)
    {
        f(sums...);
    }
};

template <typename N0, typename... Ns>
struct Pairwise<N0, Ns...>
{
    template <typename F, typename T, typename... Args>
    static void Sum(F f, N0 num0, Ns... nums, T const& a, Args&&... sums)
    {
        Pairwise<Ns...>::Sum(f, nums..., a, sums..., num0 + std::get<sizeof...(Args)>(a));
    }
};

template <typename... Ns>
void ForwardToFuncIncreased(Ns... nums)
{
    Pairwise<Ns...>::Sum(Func, nums..., summands_);
}