Skip to content

Instantly share code, notes, and snippets.

@jbelloncastro
Created January 28, 2020 17:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jbelloncastro/6e693260a5566b4ff6fee7e4f28a77d8 to your computer and use it in GitHub Desktop.
Save jbelloncastro/6e693260a5566b4ff6fee7e4f28a77d8 to your computer and use it in GitHub Desktop.
Double dispatch C++
enum class Kind : unsigned int;
struct Base {
const Kind kind;
explicit Base(Kind kind) : kind(kind) {}
template <class T> bool is() const { return kind == T::kind; }
template <class T> const T* cast() const { return is<T>()? static_cast<const T*>(this) : nullptr; }
};
#define SUBCLASSES \
declare(A) \
declare(B) \
declare(C) \
declare(D) \
declare(E) \
declare(F) \
declare(G) \
declare(H)
enum class Kind : unsigned int {
#define declare(name) name,
SUBCLASSES
#undef declare
};
#define declare(name) struct name : Base { static const Kind kind; name() : Base{name::kind} {} };
SUBCLASSES
#undef declare
#define declare(name) constexpr Kind name::kind = Kind::name;
SUBCLASSES
#undef declare
#include <utility>
struct CallbackBase {
virtual ~CallbackBase() {}
virtual void operator()(const Base *) const {}
#define declare(name) virtual void operator()(const name *p) const { (*this)(static_cast<const Base*>(p)); }
SUBCLASSES
#undef declare
};
extern void c(Kind);
template <class Arg, class Cb>
struct Callback : virtual CallbackBase {
Callback(Cb&& cb) : cb(std::forward<Cb>(cb)) {}
void operator()(Arg arg) const override { c(arg->kind); cb(std::forward<Arg>(arg)); }
Cb cb;
};
template <class... Ts>
struct overload {};
template <class T, class... Ts>
struct overload<T,Ts...> : T, overload<Ts...> {
using T::operator();
overload(T&& t, Ts&&... ts) : T{std::forward<T>(t)}, overload<Ts...>{std::forward<Ts>(ts)...} {}
};
template <class... Args, class... Ts>
auto make_callback(Ts&&... ts) {
return overload<Callback<Args,Ts>...>{std::forward<Ts>(ts)...};
}
#define declare(name) if (auto p = base.cast<name>()) { return cb(p); }
void dispatch(const Base &base, CallbackBase &cb) {
SUBCLASSES
}
#undef declare
int foo() {
int ret = 2;
G a;
auto one = [&ret](const A*) { ret = 1; };
auto zero = [&ret](const B*) { ret = 0; };
auto cb = make_callback<const A*, const B*>(one, zero);
dispatch(a, cb);
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment