[SOLVED] c++ Extract parameter type list from function pointer

Issue

Im trying to get the argument types from a function pointer

This should be the working end product

std::function<void(TestAppObject*, MemberFuncArgs<decltype(&TestAppObject::TestMethod)>::InputArgs)> func = &TestAppObject::TestMethod;

Current MemberFuncArgs class

template<typename T>
struct MemberFuncArgs;

template<typename RT, typename Owner, typename ...Args>
struct MemberFuncArgs<RT(Owner::*)(Args...)>
{
    static const size_t ArgCount = sizeof...(Args);
    typedef RT ReturnType;
    typedef Args InputArgs;
};

Compiler throws the error 'Args': parameter pack must be expanded in this context.

I just need a way to extract the Args... type from the function pointer, its probably just a syntax issue that im too dumb to see…

Solution

The compiler say the you can’t define a single type InputArgs

typedef Args InputArgs;

given that Args is a variadic list.

Maybe you can define a type base on a tuple

using InArgsTuple = std::tuple<Args...>;

so you can extract the single types in Args... using std::tuple_element

So, with a little template meta-programming, you should be able to write something as

using TplT = MemberFuncArgs<decltype(&TestAppObject::TestMethod)>::InArgsTuple;

std::function<void(TestAppObject*, typename std::tuple_element<Is, TplT>::type ...)>
   func = &TestAppObject::TestMethod;

assuming that Is... is a variadic sequence of template integer values from zero to sizeof...(Args)-1.

The following is a full compiling C++20 example

#include <tuple>
#include <functional>

struct TestAppObject
{
  int TestMethod (char, short, int, long, long long)
  { return 0; }
};

template <typename T>
struct MemberFuncArgs;

template <typename RT, typename Owner, typename ... Args>
struct MemberFuncArgs<RT(Owner::*)(Args...)>
{
  static constexpr std::size_t ArgCount = sizeof...(Args);

  using ReturnType  = RT;
  using InArgsTuple = std::tuple<Args...>;
};
    
int main()
{
  using MFA  = MemberFuncArgs<decltype(&TestAppObject::TestMethod)>;
  using FunT = decltype([]<std::size_t ... Is>(std::index_sequence<Is...>)
     -> std::function<void(TestAppObject*,
           typename std::tuple_element<Is, MFA::InArgsTuple>::type ...)>
     { return {}; }
     (std::make_index_sequence<MFA::ArgCount>{}));

  FunT  func = &TestAppObject::TestMethod;
}

If you can’t use C++20 (so no template lambda and no lambda in not evaluated context) you can substitute the lambda with a traditional template function, only declared (because is used only inside decltype().

The following is a full compiling C++14/C++17 example.
#include
#include

struct TestAppObject
{
  int TestMethod (char, short, int, long, long long)
  { return 0; }
};

template <typename T>
struct MemberFuncArgs;

template <typename RT, typename Owner, typename ... Args>
struct MemberFuncArgs<RT(Owner::*)(Args...)>
{
  static constexpr std::size_t ArgCount = sizeof...(Args);

  using ReturnType  = RT;
  using InArgsTuple = std::tuple<Args...>;
};

template <typename MFA, std::size_t ... Is>
std::function<void(TestAppObject*,
   typename std::tuple_element<Is, typename MFA::InArgsTuple>::type ...)>
      extra_function (std::index_sequence<Is...>);

int main()
{
  using MFA  = MemberFuncArgs<decltype(&TestAppObject::TestMethod)>;
  using FunT = decltype(extra_function<MFA>
                           (std::make_index_sequence<MFA::ArgCount>{}));

  FunT  func = &TestAppObject::TestMethod;
}

Answered By – max66

Answer Checked By – Mary Flores (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published.