The great problem is detect the number of arguments of F.
As pointed by Igor Tandetnik in a comment, this isn't possible in general, because the f func can be variadic, of a lambda with a template operator(), or a instance of a class/struct with multiple operator().
Anyway... in some cases you can detect the number of the arguments with something as follows
template <typename T>
struct num_args
: public num_args<decltype(&T::operator())>
{ };
template <typename R, typename ... Args>
struct num_args<R(*)(Args...)>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
// other specialization follows
At this point, you can write combine() to call an helper function with an appropriate couple of indexes and a tuple of arguments
template <typename F, typename ... Args>
void combine (F & func, Args && ... as)
{
constexpr auto n1 { num_args<F>::value };
constexpr auto n2 { sizeof...(Args) - n1 };
combine_helper(std::make_index_sequence<n1>{},
std::make_index_sequence<n2>{},
func,
std::forward_as_tuple(std::forward<Args>(as)...));
}
and the helper function can be simply as follows
template <std::size_t ... Is1, std::size_t ... Is2, typename F, typename T>
void combine_helper (std::index_sequence<Is1...>,
std::index_sequence<Is2...>,
F & func, T && t)
{
func(std::get<Is1>(std::forward<T>(t))...);
(std::cout << ... << std::get<sizeof...(Is1)+Is2>(std::forward<T>(t)))
<< '\n';
}
The following is a full compiling C++17 example
#include <iostream>
#include <utility>
#include <tuple>
template <typename T>
struct num_args
: public num_args<decltype(&T::operator())>
{ };
template <typename R, typename ... Args>
struct num_args<R(*)(Args...)>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename R, typename ... Args>
struct num_args<R(Args...)>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename R, typename C, typename ... Args>
struct num_args<R(C::*)(Args...)>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename R, typename C, typename ... Args>
struct num_args<R(C::*)(Args...) const>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <std::size_t ... Is1, std::size_t ... Is2, typename F, typename T>
void combine_helper (std::index_sequence<Is1...>,
std::index_sequence<Is2...>,
F & func, T && t)
{
func(std::get<Is1>(std::forward<T>(t))...);
(std::cout << ... << std::get<sizeof...(Is1)+Is2>(std::forward<T>(t)))
<< '\n';
}
template <typename F, typename ... Args>
void combine (F & func, Args && ... as)
{
constexpr auto n1 { num_args<F>::value };
constexpr auto n2 { sizeof...(Args) - n1 };
combine_helper(std::make_index_sequence<n1>{},
std::make_index_sequence<n2>{},
func,
std::forward_as_tuple(std::forward<Args>(as)...));
}
void func_1 (int a, int b, int c)
{ std::cout << "the product is: " << a*b*c << '\n'; }
int main()
{
auto extra { 100 };
auto func_2 { [&](int a, int b, int c, int d)
{ std::cout << "the extra sum is: " << extra+a+b+c+d << '\n'; } };
combine(func_1, 1, 2, 3, 4, 5, 6);
combine(func_2, 1, 2, 3, 4, 5, 6);
}
Fcould e.g. be a class with multiple overloads ofoperator(), taking different numbers of arguments. Or anoperator()that's itself a variadic template. It should be possible to do something like "find the longest prefix ofargs...thatfis callable with".