Skip to content

Instantly share code, notes, and snippets.

@mejedi
Last active December 19, 2015 01:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mejedi/5875719 to your computer and use it in GitHub Desktop.
Save mejedi/5875719 to your computer and use it in GitHub Desktop.
// Here be dragons
template <typename Visitor>
struct VisitorBase {
template<typename T>
void visit(T &c) {
T::template VisitorContinuation__<Visitor,0>::invoke(static_cast<Visitor&>(*this), c);
}
};
#define STRUCT(name) \
struct name { \
typedef name ThisType__; \
template<typename Visitor, int Tier> \
struct VisitorContinuation__ { \
static void invoke(Visitor &visitor, ThisType__ &c) {} \
}; \
enum { COUNTER_BASE__ = __COUNTER__ }; // technically this is ODR violation but we can probably get away with it
#define FIELD(name, type) \
type name; \
template<typename Visitor> \
struct VisitorContinuation__<Visitor,(__COUNTER__-COUNTER_BASE__-1)/2> { \
static void invoke(Visitor &visitor, ThisType__ &c) { \
visitor.visit_field(# name, c.name); \
VisitorContinuation__<Visitor,(__COUNTER__-COUNTER_BASE__)/2>::invoke(visitor, c); \
} \
};
#define END_STRUCT \
};
// Here be dragons no longer
#include <cstdio>
struct Printer: VisitorBase<Printer>
{
void visit_field(const char *name, int val) {
::printf("%s %d\n", name, val);
}
void visit_field(const char *name, float val) {
::printf("%s %.3f\n", name, val);
}
};
STRUCT(Dummy)
FIELD(foo, int)
FIELD(bar, int)
END_STRUCT
STRUCT(Point3D)
FIELD(x, float)
FIELD(y, float)
FIELD(z, float)
END_STRUCT
int main()
{
Dummy dummy;
dummy.foo = 42;
dummy.bar = 0;
Point3D point;
point.x = 1.f;
point.y = -1.f;
point.z = .5f;
Printer printer;
printer.visit(dummy);
printer.visit(point);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment