1

I want to implement something like the following member function (method), which is supposed to increase each argument by some summand (addend) corresponding to the argument index and forward it to another variadic-template function:

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
}

where summands_ is a member variable of type std::tuple or std::array (you can assume either). The basic requirement is that it should have no runtime overhead compared to:

Func(int0 + std::get<0>(summands_), int1 + std::get<1>(summands_), ...);

(Imagine I overload the function for up to N template parameters).

If it is not possible to do it without necessary runtime overhead, I am willing to go with certain modifications (esp. in the way of storing additional stuff in my class or modifying the type).

Note: My intention is not to extract the template argument indexes, but hopefully to achieve what I need without it.

eold
  • 5,972
  • 11
  • 56
  • 75

1 Answers1

2

In C++14, you'll be able to do the following, very similar to your original attempt:

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...>());
}

In the meantime, you could find or write your own implementation of index_sequence.

Or do something like this: First doing std::make_tuple(ints...) so that we have two tuples which we want to sum (or a tuple and a std::array). Then using the pattern demonstrated by Andrei Alexandrescu in The Way of the Exploding Tuple to expand the sum into a parameter pack which is passed to 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_);
}

It's also possible to do it without the initial 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_);
}
Oktalist
  • 14,336
  • 3
  • 43
  • 63