I made a template function which takes a member function as a parameter.
However, since the class has to be declared before it can be used as part of the member function parameter, I have to make it a separate parameter:
template<typename C, void (C::*Method)(void)>
function<void(C*)> methodWrap()
{
}
Which means when explicitly instantiate the template (I want these wrappers to be generated at compile time, not passing in a member pointer as an argument) I have to type it twice when I use it:
function<void(C*)> someFunc = wrapMethod<SomeClass, &SomeClass::someMethod>();
Why can't I just write something like tis:
template<void (C::*Method)(void)>
function<void(C*)> methodWrap()
{
}
and let it capture the type of C and its member function pointer without having to type SomeClass twice?
Or why can't I wrapper it in an outer template that declares C as a "free variable" and then has an inner template argument that performs the deduction
template<typename C>
template<void (C::*Method)(void)>
function<void(C*)> methodWrap()
{
}
If you can live with having a normal function parameter for the member function pointer instead of making it a template parameter, you can do
#include <functional>
template<typename R, typename C, typename... Args>
struct MemberFunctionPointer
{
typedef R Return;
typedef C Class;
};
template<typename R, typename C>
constexpr auto inferMemberFunctionPointer(R (C::*method)())
{
return MemberFunctionPointer<R,C>{};
}
template<typename T>
constexpr auto methodWrap(T m)
{
typedef typename decltype(inferMemberFunctionPointer(m))::Class Class;
typedef typename decltype(inferMemberFunctionPointer(m))::Return Return;
return std::function<Return (Class*)>();
}
struct B {};
struct A
{
B f();
};
void foo()
{
auto const m = methodWrap( &A::f );
}
std::function
is not a constexpr
type, so we cannot use methodWrap to initialize a constexpr
variable. You can bypass this by creating your own simple constexpr
member function wrapper. I've also added a static_assert
to get better error messages.
#include <functional>
template<typename R, typename C, typename... Args>
struct MemberFunctionPointer
{
typedef R Return;
typedef C Class;
};
template<typename R, typename C>
constexpr auto inferMemberFunctionPointer(R (C::*method)() const)
{
return MemberFunctionPointer<R,C>{};
}
template<typename R, typename C>
struct MemberFunction
{
constexpr explicit MemberFunction(R (C::*g)() const): f(g) {}
constexpr R operator()(C const* obj) const
{
return (obj->*f)();
}
R (C::*f)() const;
};
template<typename T>
constexpr auto methodWrap(T m)
{
static_assert( std::is_member_function_pointer<T>::value,
"Member function pointer expected!");
typedef typename decltype(inferMemberFunctionPointer(m))::Class Class;
typedef typename decltype(inferMemberFunctionPointer(m))::Return Return;
return MemberFunction<Return, Class>{ MemberFunctionPointer<Return,Class>{} };
}
struct B {};
struct A
{
constexpr B f() const;
};
void foo()
{
auto constexpr m = methodWrap( &A::f );
auto constexpr a = A{};
m( &a );
auto b = A{};
m( &b );
}