Assume I have function that accept 1 callable F and variadic list of arguments:
template <class F, class ...Args>
void combine(F& f, Args&& ... args)
F
may have any number of arguments from 1 to sizeof...(Args)
. So I need using c++17 to invoke F
and after that just put not used args to std::cout
like that
{
std::invoke(f, [some way to restrict args]);
std::cout << [The rest of args] << "\n";
}
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);
}