#include <iostream>
#include <type_traits>
#include <utility>
#include <functional>
template<class...>
using void_t = void;
template<class C, class E, class X = void_t<>>
struct has_receive_member : std::false_type {};
template<class C, class E>
#define TRAIT_CASE decltype(std::declval<C>().receive(std::declval<const E&>()))
struct has_receive_member<C, E, void_t<TRAIT_CASE>> : std::true_type {};
template<class...> class Dispatcher;
template<class E, class... F>
class Dispatcher<E, F...>
{
public:
template<class C>
std::enable_if_t<has_receive_member<C, E>::value> registerHandler(C& callback)
{
using namespace std::placeholders;
handlerFunction = std::bind(static_cast<void(C::*)(const E&)>(&C::receive), callback, _1);
base.registerHandler(callback);
}
void call(const E& event)
{
handlerFunction(event);
}
template<class G>
void call(const G& event)
{
base.call(event);
}
private:
std::function<void(const E&)> handlerFunction;
Dispatcher<F...> base;
};
template<>
class Dispatcher<>
{
public:
template<class C>
void registerHandler(C& callback) {};
template<class E>
void call(const E& event)
{
static_assert(!std::is_same<E, E>::value,
"Does not handle this type of event.");
}
};
struct E1 {};
struct E2 {};
struct E3 {};
struct handler
{
void receive(const E1&)
{
std::cout << "E1\n";
}
void receive(const E2&)
{
std::cout << "E2\n";
}
void receive(const E3&)
{
std::cout << "E3\n";
}
};
static_assert(has_receive_member<handler, E1>::value, "E1");
static_assert(has_receive_member<handler, E2>::value, "E2");
static_assert(has_receive_member<handler, E3>::value, "E3");
int main()
{
handler h;
h.receive(E1{});
h.receive(E2{});
h.receive(E3{});
// via dispatcher
Dispatcher<E1, E2, E3> d;
d.registerHandler(h);
d.call(E1{});
d.call(E2{});
d.call(E3{});
}