Program Listing for File visitor.hpp

Return to documentation for file (rcppsw/patterns/visitor/visitor.hpp)

#pragma once

/*******************************************************************************
 * Includes
 ******************************************************************************/
#include <utility>

#include <boost/variant/static_visitor.hpp>

#include "rcppsw/rcppsw.hpp"
#include "rcppsw/mpl/typelist.hpp"

/*******************************************************************************
 * Namespaces/Decls
 ******************************************************************************/
namespace rcppsw::patterns::visitor {

/*******************************************************************************
 * Class Definitions
 ******************************************************************************/
namespace detail {
template <typename T>
class visit_set_helper {
 public:
  virtual void visit(T& visitee) = 0;
  virtual ~visit_set_helper(void) = default;
};

} /* namespace detail */

template <typename... Ts>
class visit_set {};

template<typename T, typename... Ts>
class visit_set<T, Ts...>: public detail::visit_set_helper<T>,
                           public visit_set<Ts...> {
 public:
  using detail::visit_set_helper<T>::visit;
  using visit_set<Ts...>::visit;
};

template<typename T>
class visit_set<T>: public detail::visit_set_helper<T> {
 public:
  using detail::visit_set_helper<T>::visit;
};

template<typename ...Args>
using precise_visit_set = mpl::typelist<Args...>;

template <typename VisitorImpl, typename TypeList>
class precise_visitor : public VisitorImpl,
                        protected boost::static_visitor<void> {
 public:
  using VisitorImpl::VisitorImpl;
  template <typename... Args>
  explicit precise_visitor(Args&&... args)
      : VisitorImpl(std::forward<Args>(args)...) {}

  template <typename T,
            RCPPSW_SFINAE_TYPELIST_REQUIRE(TypeList, T),
            typename ...Args>
  void visit(T& visitee, Args&&... args) {
    VisitorImpl::visit(visitee, std::forward<Args>(args)...);
  }
};

template<typename TVisitor>
class filtered_visitor {
 public:
  using visitor_type = TVisitor;
  template<typename...Args>
  explicit filtered_visitor(Args&& ...args)
      : m_impl(std::forward<Args>(args)...) {}

  template<typename TAny, typename ...Args>
  void visit(TAny& obj, Args&&... args) {
    m_impl.visit(obj, std::forward<Args>(args)...);
  }

 private:
  precise_visitor<TVisitor, typename TVisitor::visit_typelist> m_impl;
};

} /* namespace visitor::patterns::rcppsw */