Skip to content

Instantly share code, notes, and snippets.

@gchudnov
Created December 18, 2015 15:45
Show Gist options
  • Save gchudnov/30c158f871de24aea6dd to your computer and use it in GitHub Desktop.
Save gchudnov/30c158f871de24aea6dd to your computer and use it in GitHub Desktop.
inline_visitor_builder
#include <iostream>
#include <vector>
// inline visitor
struct triangle;
struct square;
struct figure_visitor {
virtual ~figure_visitor() = default;
virtual void visit(const triangle&) {}
virtual void visit(const square&) {}
};
struct figure {
virtual void accept(figure_visitor&) = 0;
};
struct triangle: figure {
void accept(figure_visitor& v) override {
v.visit(*this);
}
};
struct square : figure {
void accept(figure_visitor& v) override {
v.visit(*this);
}
};
//
template <typename T, typename F, typename BaseInner, typename ArgsT>
struct CompositeVisitor {
struct Inner : public BaseInner {
using BaseInner::visit;
Inner(ArgsT&& args)
: BaseInner(std::move(args.second)),
f_(std::move(args.first)) {
// no-op
}
void visit(const T& t) override final {
f_(t);
}
F f_;
};
CompositeVisitor(ArgsT&& args)
: args_(std::move(args)) {
// no-op
}
template <typename Tadd, typename Fadd>
CompositeVisitor<Tadd, Fadd, Inner, std::pair<Fadd, ArgsT>> on(Fadd&& f) {
return CompositeVisitor<Tadd, Fadd, Inner, std::pair<Fadd, ArgsT>>(std::make_pair(std::move(f), std::move(args_)));
};
Inner end_visitor() {
return Inner(std::move(args_));
}
ArgsT args_;
};
template <typename VBase>
struct EmptyVisitor {
struct Inner : public VBase {
using VBase::visit;
Inner(std::nullptr_t) {
// no-op
}
};
template <typename Tadd, typename Fadd>
CompositeVisitor<Tadd, Fadd, Inner, std::pair<Fadd, std::nullptr_t>> on(Fadd&& f) {
return CompositeVisitor<Tadd, Fadd, Inner, std::pair<Fadd, std::nullptr_t>>(std::make_pair(std::move(f), nullptr));
};
};
template <typename VBase>
EmptyVisitor<VBase> begin_visitor() {
return EmptyVisitor<VBase>();
}
//
int count_sides(figure& f) {
int sides = 0;
auto v = begin_visitor<figure_visitor>()
.on<square>([&sides](const square& sq) { sides = 4; })
.on<triangle>([&sides](const triangle& tr) { sides = 3; })
.end_visitor();
f.accept(v);
return sides;
}
int main() {
triangle t;
square s;
std::cout << count_sides(t) << std::endl;
std::cout << count_sides(s) << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment