Zang MingJie
Zang MingJie

Reputation: 5275

Get function arguments type as tuple

Problem

Given any function (or callable) type Function, how can I get its all arguments types as a tuple type ?

For example, I need a trait function_traits<Function>::arguments, where:

int f();
typename function_traits<decltype(f)>::arguments // => gives me std::tuple<>

void g(int);
typename function_traits<decltype(g)>::arguments // => gives me std::tuple<int>

void h(int, int);
typename function_traits<decltype(h)>::arguments // => gives me std::tuple<int, int>

My thought

First

I need to get the size of arguments, fortunately boost already has implemented function_traits<F>::arity

Then

Generate an std::integer_sequence from 1 to artify, map it to arguments type, but here comes the problem, to map integer_sequence, I need something like this:

function_traits<F>::arg_type<N> // -> N-th arg_type

but boost only provides this:

function_traits<F>::argN_type

Question

How can I implement function_traits<F>::arg_type<N> ? I can use c++ standard up to c++17

Upvotes: 10

Views: 3038

Answers (2)

max66
max66

Reputation: 66210

Is too late to play?

You can use C++17 so... what about using std::function deduction guides?

template <typename T>
struct function_traits
 {
   template <typename R, typename ... As>
   static std::tuple<As...> pro_args (std::function<R(As...)>);

   using arguments = decltype(pro_args(std::function{std::declval<T>()}));
 };

The following is a full compiling example

#include <tuple>
#include <functional>
#include <type_traits>

int f ();
void g (int);
void h (int, int);

template <typename T>
struct function_traits
 {
   template <typename R, typename ... As>
   static std::tuple<As...> pro_args (std::function<R(As...)>);

   using arguments = decltype(pro_args(std::function{std::declval<T>()}));
 };

int main ()
 {
   static_assert(std::is_same_v<std::tuple<>,
                 function_traits<decltype(f)>::arguments>);

   static_assert(std::is_same_v<std::tuple<int>,
                 function_traits<decltype(g)>::arguments>);

   static_assert(std::is_same_v<std::tuple<int, int>,
                 function_traits<decltype(h)>::arguments>);
 }

Upvotes: 5

user7860670
user7860670

Reputation: 37597

Something like this:

#include <tuple>

template<typename x_Function> class
function_traits;

// specialization for functions
template<typename x_Result, typename... x_Args> class
function_traits<x_Result (x_Args...)>
{
    public: using arguments = ::std::tuple<x_Args...>;
};

usage example:

#include <type_traits>

int foo(int);

using foo_arguments = function_traits<decltype(foo)>::arguments;
static_assert(1 == ::std::tuple_size<foo_arguments>::value);
static_assert(::std::is_same_v<int, ::std::tuple_element<0, foo_arguments>::type>);

online compiler

Upvotes: 8

Related Questions