I have a function f1()
template <typename... Args>
void f1(Args... args)
{
// the implementation is just an example, I don't really need a complicated
// way to sum numbers
boost::fusion::vector<Args...> v(args...);
std::cout << boost::fusion::accumulate(v, 0, [](auto i1, auto i2) { return i1 + i2; }) << std::endl;
}
I want to call it from a function f2()
, but with a different last argument. Is there a simple approach? I tried a naive one
template <typename... Args>
struct CallHelper;
template <>
struct CallHelper<>
{
template <typename... Args>
static void Apply(Args... args) { f1(args...); }
};
template <typename A0>
struct CallHelper<A0>
{
template <typename... Args>
static void Apply(Args ...args, A0 a0)
{
// substitute 10 to the last argument
CallHelper<>::Apply(args..., 10);
}
};
template <typename Head, typename ...TailArgs>
struct CallHelper<Head, TailArgs...>
{
template <typename... Args>
static void Apply(Args... args, Head head, TailArgs ...tailArgs)
{
CallHelper<TailArgs...>::Apply(args..., head, tailArgs...);
}
};
template <typename... Args>
void f2(Args... args)
{
CallHelper<Args...>::Apply(args...);
}
Of course it doesn't work, because Head head
is not the first argument. Maybe there is a way to make Head head
a parameter pack as well? Or there is something else I can do?
You might forward your arguments as tuple and then unpack all except the last one using std::integer_sequence
. This code looks much simpler than your approach:
template<typename... Args>
void f1(Args... args)
{
boost::fusion::vector<Args...> v(args...);
std::cout << boost::fusion::accumulate(v, 0, [](auto i1, auto i2) { return i1 + i2; }) << std::endl;
}
template<typename Tuple, size_t... idx>
void callImpl(Tuple&& tuple, std::index_sequence<idx...>)
{
f1(std::get<idx>(std::forward<Tuple>(tuple))..., 10);
}
template<typename... Ts>
void callWithLast10(Ts&&... ts)
{
callImpl(std::forward_as_tuple(ts...), std::make_index_sequence<sizeof...(Ts) - 1>());
}
Usage:
f1(1, 2, 3, 4); // Prints 10
callWithLast10(1, 2, 3, 4); // Prints 16
With the help of index sequences...
#include <utility>
#include <iostream>
template <typename ... Args>
void f1 (Args ... args)
{
using unused=int[];
(void)unused { 0, (std::cout << args << ", ", 0)... };
std::cout << std::endl;
}
template <std::size_t>
struct getVal
{
template <typename T1, typename T2>
T2 operator() (T1 const &, T2 const & t2)
{ return t2; }
};
template <>
struct getVal<0U>
{
template <typename T1, typename T2>
T1 operator() (T1 const & t1, T2 const &)
{ return t1; }
};
template <std::size_t ... Is, typename ... Args>
void f2_helper (std::index_sequence<Is...> const &, Args const & ... args)
{ f1 ( getVal<sizeof...(Is)-Is-1U>()(10, args)... ); }
template <typename ... Args>
void f2 (Args ... args)
{ f2_helper(std::make_index_sequence<sizeof...(Args)>{}, args...); }
int main()
{
f1(1, 2L, 3.3, "ten"); // print 1, 2, 3.3, ten,
f2(1, 2L, 3.3, "ten"); // print 1, 2, 3.3, 10,
}
It's a C++14 solution (require std::index_sequence
and std::make_index_sequence
) but should be simple create substitutes for C++11, if you need they.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With