I would like to wrap member functions that conform to the type \'void (ClassType::Function)(ArgType)\' with a templated class. Later, I want to pass an instance of ClassType to
struct MyClass
{
MyClass& Move(MyClass& m) { return *this; }
};
typedef MyClass& (MyClass::*MethodT) (MyClass&);
template< typename T >
struct ExtractType : std::false_type
{
};
template< typename R, typename C, typename A >
struct ExtractType< R (C::*)(A) >
{
typedef C type;
};
static_assert( std::is_same< ExtractType< MethodT >::type, MyClass >::value, "oops" );
It appears to work in my version of gcc 4.8.
It works like I mentioned in the comment, its a "back pattern matching" that the compiler does during specialization checks. This is very powerful.
So you see, we specified some kind of pattern that if the type T
respects, it will be decomposed by the compiler into the three subtypes that composes it: R
, C
, A
. Which is return type, class type and argument.
However you can see that it works with one argument. How to do when we have an undefined number of arguments ?
Maybe a list of checker classes, or use variadic templates ?
And frankly in all honesty, I am not even sure this will work with void
. I think void is always impossible to place in template, therefore it will result in many versions of this ExtractType
class to support all combinations of possible declarations. Or so it seems to me.
EDIT:
Ok so I'm giving this away completely randomly, but it seems in C++11 it works much better than I have expected, this is ok on gcc 4.8:
struct MyClass
{
};
typedef int (MyClass::*MethodT) (bool);
typedef void (MyClass::*VV) ();
typedef void (MyClass::*IL) (int, long);
template< typename T >
struct ExtractType : std::false_type
{
};
template< typename R, typename C, class...A >
struct ExtractType< R (C::*)(A...) >
{
typedef C type;
typedef R returntype;
};
static_assert( std::is_same< ExtractType< MethodT >::type, MyClass >::value, "oops" );
static_assert( std::is_same< ExtractType< VV >::type, MyClass >::value, "oops" );
static_assert( std::is_same< ExtractType< IL >::type, MyClass >::value, "oops" );
static_assert( std::is_same< ExtractType< MethodT >::returntype, int >::value, "oops" );
static_assert( std::is_same< ExtractType< VV >::returntype, void >::value, "oops" );
static_assert( std::is_same< ExtractType< IL >::returntype, void >::value, "oops" );
The crazy part being that it doesn't mind void
in the return type. Of course its C++11 however.