#pragma once #include #include #include #include /* Generic utils which are intended for visitor pattern implementation. * The original purpose is to provide possibility to get concrete template specialisation for type in list. * * Usage: * 1. Declare visitor interface base class for types T_1, ..., T_N: * class MyVisitor : public Visitor {}; * 2. Declare visitor implementation base class using VisitorImpl: * template * class MyVisitorImpl : public VisitorImpl {}; * 3. Add virtual function 'accept' to common base of T_1, ..., T_N: * class T_Base * { * ... * public: * virtual void accept(MyVisitor &) { throw Exception("Accept not implemented"); } * }; * 4. Declare base class for T_1, ..., T_N implementation: * template * class T_Impl : public Visitable {}; * 5. Implement 'accept' for each T_i: * a) inherit from T_Impl: * class T_i : public T_Impl { ... }; * b) or in order to avoid ambiguity: * class T_i * { * ... * public: * void accept(MyVisitor & visitor) override { visitor.visit(*this); } * }; * 6. Implement concrete visitor with visitImpl template function: * class MyConcreteVisitor : public MyVisitorImpl * { * ... * public: * template * void visitImpl(T & t) { ... } * }; * 7. Now you can call concrete implementation for MyConcreteVisitor: * MyConcreteVisitor visitor; * T_Base * base; * base->accept(visitor); /// call MyConcreteVisitor::visitImpl(T & t) * * TODO: Add ConstVisitor with 'visit(const Type &)' function in order to implement 'accept(...) const'. */ namespace DB { namespace ErrorCodes { extern const int LOGICAL_ERROR; } template class Visitor; template <> class Visitor<> { public: using List = TypeList<>; protected: ~Visitor() = default; }; template class Visitor : public Visitor<> { public: using List = TypeList; virtual void visit(Type &) = 0; protected: ~Visitor() = default; }; template class Visitor : public Visitor { public: using List = TypeList; using Visitor::visit; virtual void visit(Type &) = 0; protected: ~Visitor() = default; }; template class VisitorImplHelper; template class VisitorImplHelper : public VisitorBase { protected: ~VisitorImplHelper() = default; }; template class VisitorImplHelper : public VisitorBase { public: using VisitorBase::visit; void visit(Type & value) override { static_cast(this)->visitImpl(value); } protected: template void visitImpl(Type &) { throw Exception("visitImpl(" + demangle(typeid(T).name()) + " &)" + " is not implemented for class" + demangle(typeid(Derived).name()), ErrorCodes::LOGICAL_ERROR); } ~VisitorImplHelper() = default; }; template class VisitorImplHelper : public VisitorImplHelper { public: using VisitorImplHelper::visit; void visit(Type & value) override { static_cast(this)->visitImpl(value); } protected: template void visitImpl(Type &) { throw Exception("visitImpl(" + demangle(typeid(T).name()) + " &)" + " is not implemented for class" + demangle(typeid(Derived).name()), ErrorCodes::LOGICAL_ERROR); } ~VisitorImplHelper() = default; }; template class VisitorImpl : public TypeListChangeRoot< VisitorImplHelper, TypeListConcat< TypeList, typename VisitorBase::List > > { protected: ~VisitorImpl() = default; }; template class Visitable : public Base { public: void accept(Visitor & visitor) override { visitor.visit(*static_cast(this)); } }; }