There are other answers on this site using SFINAE but with non C++11 code, and there are others using C++11 code like decltypes to make this process easier. However, I am no
There is help with macros:
#define DEFINE_METHOD_CHECKER(RETURN_TYPE, METHOD_NAME, PARAMETERS) \
template<typename T> \
struct Is ## METHOD_NAME ## MemberFunctionExists \
{ \
private: \
typedef char True; \
typedef char (&False)[2]; \
template<typename U, RETURN_TYPE (U::*)PARAMETERS = &U::METHOD_NAME>\
struct Checker \
{ \
typedef True Type; \
}; \
template<typename U> \
static typename Checker<U>::Type Tester(const U*); \
static False Tester(...); \
public: \
enum { value = (sizeof(Tester(static_cast<const T*>(0))) == sizeof(True)) }; \
}
// IsMethodMemberFunctionExists<T>::value
DEFINE_METHOD_CHECKER(int, Method, (bool));
// IsTestMemberFunctionExists<T>::value
DEFINE_METHOD_CHECKER(int*, Test, (int&, char));
#include <iostream>
class Exists
{
public:
int Method(bool);
int* Test(int&, char);
};
class NotExists
{
};
int main()
{
std::cout << IsMethodMemberFunctionExists<Exists>::value << std::endl;
std::cout << IsTestMemberFunctionExists<Exists>::value << std::endl;
std::cout << IsMethodMemberFunctionExists<NotExists>::value << std::endl;
std::cout << IsTestMemberFunctionExists<NotExists>::value << std::endl;
}
So, in your case you need to define a few checkers - one checker for one type of Event:
// void recieve(const Event1&)
DEFINE_METHOD_CHECKER(void, recieve, (const Event1&));
// void recieve(const Event2&)
DEFINE_METHOD_CHECKER(void, recieve, (const Event2&));
The best way I know of is checking if you can actually call the function and if it returns the type you expect. Here's an example of how to detect if a class C
has a receive
method which takes const Event&
as a parameter and "returns" void
. The detection does not care whether the method is implemented in the class C
directly or in some base class that C
derives from, neither does it care whether there are further defaulted parameters. Adapt as needed.
template< typename C, typename Event, typename = void >
struct has_receive
: std::false_type
{};
template< typename C, typename Event >
struct has_receive< C, Event, typename std::enable_if<
std::is_same<
decltype( std::declval<C>().receive( std::declval<const Event&>() ) ),
void
>::value
>::type >
: std::true_type
{};
You may use the following to match exact signature:
template <typename U, typename Event>
class has_receive
{
private:
template<typename T, T> struct helper;
template<typename T>
static std::uint8_t check(helper<void (T::*)(const Event &), &T::receive>*);
template<typename T> static std::uint16_t check(...);
public:
static
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t);
};