#pragma once #include #include #include #include namespace jvalidate::extension { struct VisitorBase { virtual ~VisitorBase() = default; }; template concept Constraint = std::is_base_of_v; namespace detail { template struct TypedVisitor : VisitorBase { virtual Status visit(E const & cons) const = 0; }; template struct TypedVisitorImpl : TypedVisitor { Status visit(E const & cons) const final { return static_cast(this)->dispatch(cons); } }; } template struct ConstraintBase : constraint::ExtensionConstraint::Impl { Status visit(VisitorBase const & visitor) const final { return dynamic_cast const &>(visitor).visit( static_cast(*this)); } }; template class Visitor { private: template class Impl : public detail::TypedVisitorImpl>... { public: Impl(Visitor const * self, A const & document, V const & visitor) : self_(self), document_(document), visitor_(visitor) {} using detail::TypedVisitorImpl::visit...; template Status dispatch(E const & cons) const { // static_assert(Visitable, "Must implement all visitation functions"); return static_cast(self_)->visit(cons, document_, visitor_); } private: Visitor const * self_; A const & document_; V const & visitor_; }; public: template Status operator()(constraint::ExtensionConstraint const & cons, A const & document, V const & visitor) const { return cons.pimpl->visit(Impl{this, document, visitor}); } }; }