Skip to content

Instantly share code, notes, and snippets.

@dkorolev
Created April 26, 2015 05:43
Show Gist options
  • Save dkorolev/832afbbfa134815b1c9b to your computer and use it in GitHub Desktop.
Save dkorolev/832afbbfa134815b1c9b to your computer and use it in GitHub Desktop.
visitor_v2.cc
// V2: Using the type list, to allow user-defined dispatching.
#include <cstdio>
#include <vector>
#include <utility>
// Library code.
template<typename>
struct Visitor {
};
template<>
struct Visitor<std::tuple<>> {
};
template<typename T>
struct VirtualVisitMethod {
virtual void Visit(T&) = 0;
};
template<typename T, typename... TS>
struct Visitor<std::tuple<T, TS...>> : Visitor<std::tuple<TS...>>, VirtualVisitMethod<T> {
};
template<typename TYPELIST>
struct AbstractVisitable {
virtual void Accept(Visitor<TYPELIST>&) = 0;
};
template<typename TYPELIST, typename T>
struct Visitable : AbstractVisitable<TYPELIST> {
virtual void Accept(Visitor<TYPELIST>& v) override {
static_cast<VirtualVisitMethod<T>&>(v).Visit(*static_cast<T*>(this));
}
};
// User simple code (defining visitable classes, with non-virtual methods).
using TypelistAB = std::tuple<struct A, struct B>;
using TypelistBC = std::tuple<struct B, struct C>;
struct A : Visitable<TypelistAB, A> {
int a = 101;
void foo() {
printf("A::foo(%d)\n", a);
}
};
struct B : Visitable<TypelistAB, B>, Visitable<TypelistBC, B> {
int b = 102;
void bar() {
printf("B::bar(%d)\n", b);
}
};
struct C : Visitable<TypelistBC, C> {
int c = 103;
void baz() {
printf("C::baz(%d)\n", c);
}
};
// User complex code (making use of non-virtual methods of visitable classes).
int main() {
A a;
B b;
C c;
struct FooOrBarCaller : Visitor<TypelistAB> {
// Note that forgetting to handle one of `Visit()` overrides will result in compile errors of two types:
// 1) overriding what is not `virtual`, thus attempting to operate on a parameter not from the type list, or
// 2) not overriding what should be overridden, thus attempting to instantiate the `Visitor` that is abstract.
virtual void Visit(A& a) override {
a.foo();
}
virtual void Visit(B& b) override {
b.bar();
}
} foobar;
for (auto& it : std::vector<AbstractVisitable<TypelistAB>*>({ &a, &b })) {
it->Accept(foobar);
}
struct BarOrBazCaller : Visitor<TypelistBC> {
virtual void Visit(B& b) override {
b.bar();
}
virtual void Visit(C& c) override {
c.baz();
}
} barbaz;
for (auto& it : std::vector<AbstractVisitable<TypelistBC>*>({ &b, &c })) {
it->Accept(barbaz);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment