Понадобилось реализовать паттерн Visitor, и что-то не получается придумать как сделать так чтоб было и просто и удобно и эффективно %)
(GoF читал, Александреску читал, сам думал
)
Значится есть иерархия классов
struct visitor;
struct node
{
virtual void accept(visitor* v) = 0;
};
struct some : node
{
virtual void accept(visitor* v);
};
struct other : node
{
virtual void accept(visitor* v);
};
и хочется делать таких посетителей, чтоб без кучи перегрузок виртуальных методов, например как в boost.variant
struct test_visitor
{
void operator()(some&) { std::cout << "some visited\n"; }
void operator()(other&) { std::cout << "other visited\n"; }
template<class T> void operator()(T&) { std::cout << "i-dunno-what visited\n"; }
};
int main()
{
some o;
node* n = &o;
test_visitor vis;
apply_visitor(vis, n);
}
код visitor'а и apply_visitor можно сделать таким:
struct visitor
{
virtual void visit(some&) = 0;
virtual void visit(other&) = 0;
};
template<class Vis>
inline void apply_visitor(Vis& vis, node* n)
{
struct visitor_impl : visitor
{
virtual void visit(some& n) { vis(n); }
virtual void visit(other& n) { vis(n); }
visitor_impl(Vis& vis) : vis(vis) {}
Vis& vis;
};
visitor_impl impl(vis);
n->accept(&impl);
}
void some::accept(visitor* v) { v->visit(*this); } // тут может быть нетривиальный код обхода структуры
void other::accept(visitor* v) { v->visit(*this); }
и всё бы тут вобщем-то и хорошо, но расстраивает то, что тут надо два раза перечислять классы — в visitor и в visitor_impl
хорошо бы как-нибудь шаблоны применить, чтоб этого избежать — к примеру visitor::visit совсем не обязательно должна быть виртуальной, она вполне может быть шаблонной
код полностью:
http://codepad.org/RjBdzVAh