#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(ErrorCodes::LOGICAL_ERROR, "visitImpl({} &) is not implemented for class{}",
demangle(typeid(T).name()), demangle(typeid(Derived).name()));
}
~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(ErrorCodes::LOGICAL_ERROR, "visitImpl({} &) is not implemented for class{}",
demangle(typeid(T).name()), demangle(typeid(Derived).name()));
}
~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)); }
};
}