1

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";
}

    
1
  • Not possible in general. F could e.g. be a class with multiple overloads of operator(), taking different numbers of arguments. Or an operator() that's itself a variadic template. It should be possible to do something like "find the longest prefix of args... that f is callable with". Commented Aug 23, 2021 at 15:02

1 Answer 1

2

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);
 }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.