9

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

max66
  • 65,235
  • 10
  • 71
  • 111
Zang MingJie
  • 5,164
  • 1
  • 14
  • 27

3 Answers3

8

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

user7860670
  • 35,849
  • 4
  • 58
  • 84
  • 1
    How it works ? All usage will reduce to the first type, which is not implemented at all, it will never reduce to the second one. – Zang MingJie Aug 23 '19 at 08:20
  • 1
    @ZangMingJie The template specialisation is an exact match and more specialised than the general template. That’s why usage with a function will reduce to the second type. – Konrad Rudolph Aug 23 '19 at 08:22
  • @ZangMingJie I've added usage example – user7860670 Aug 23 '19 at 08:22
  • is it possible to make it work with lambda ? or any callable, and functor ? – Zang MingJie Aug 23 '19 at 08:30
  • @ZangMingJie That would require figuring out arguments of `operator ()` member function. It can be not trivial if `operator ()` is overloaded – user7860670 Aug 23 '19 at 08:39
  • 1
    after adding member function reduce and this `template class function_traits : public function_traits {};`, it kinda works with lambda w/o auto arguments. – Zang MingJie Aug 23 '19 at 08:54
4

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>);
 }
max66
  • 65,235
  • 10
  • 71
  • 111
-1

It's now several years later but I have a very effective (free) solution if you still require it (if you're not locked into Boost). Not satisfied with the solutions I found to handle function traits, including Boost's (neither "function_traits" nor "callable_traits"), I wrote my own and made it available on GitHub for the C++ developer community. I believe it's the most complete library of its kind you'll currently find (professionally written and fully documented).

See https://stackoverflow.com/a/76253527/698767 (and the link cited there).

Note that the example there addresses your question as well.

Larry
  • 796
  • 6
  • 13