Infer the type of the class owning a member function

Viewed 64

Let's consider a kind of "invoke" function (here named "call") that helps to call a member function passed by a template argument. In this function, I would need to know the type of the class that owns the member function. Is there a way (in c++14 preferably) to do so ?

#include <functional>

template<typename F, typename... Args, std::enable_if_t<std::is_member_pointer<std::decay_t<F>>{}, int> = 0 >
constexpr decltype(auto) call(F&& f, Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
{
    // Here we know that f is a member function, so it is of form : &some_class::some_function
    // Is there a way here to infer the type some_class from f ? For exemple to instantiate a variable from it :
    // imaginary c++ : class_of(f) var;
    return std::mem_fn(f)(std::forward<Args>(args)...);
}

int main()
{
    struct Foo { void bar() {} } foo;
    call(&Foo::bar, &foo /*, args*/);
    return 0;
}
2 Answers
template <typename>
struct class_of;
template <typename C, typename R, typename... Args>
struct class_of<R(C::*)(Args...)> {
    using type = C;
};

Then you can get the type like typename class_of<F>::type. E.g.

template<typename F, typename... Args, std::enable_if_t<std::is_member_pointer<std::decay_t<F>>{}, int> = 0 >
constexpr decltype(auto) call(F&& f, Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
{
    typename class_of<F>::type var;
    return std::mem_fn(f)(std::forward<Args>(args)...);
}

BTW, It depends on your intent, but you can change the template paramters' declaration to get the class type directly.

// I remove the type check because only member function pointer could be passed in
template<typename C, typename R, typename... FArgs, typename... Args>
constexpr decltype(auto) call(R(C::*f)(FArgs...), Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
{
    C var;
    return std::mem_fn(f)(std::forward<Args>(args)...);
}

songyuanyao beat me to it, but note that you don't need to spell out the function type to deconstruct the member pointer:

template <class MemberPtr>
struct mptr_class;

template <class T, class Class>
struct mptr_class<T Class::*> {
    using type = Class;
};

template <class MemberPtr>
using mptr_class_t = typename mptr_class<MemberPtr>::type;
Related