我可以使用字体表构建抽象访问者吗?

Can I build an abstract visitor using a typelist?

本文关键字:抽象 访问者 构建 可以使 字体 我可以      更新时间:2023-10-16

所以我有一个抽象类,它是任何使用对象集合的访问者的基础:

class visitor
{
  virtual void visit(foo) = 0;
  virtual void visit(bar) = 0;
  virtual void visit(baz) = 0;
  virtual void visit(quux) = 0;
};

但是我也将所有这些类型保存在boost::mpl::list中:

using type_list = boost::mpl::list<
  foo,
  bar,
  baz,
  quux
>;

每当我添加新类型时,都必须更新访问者类似乎是一种耻辱......有什么方法可以通过传递type_list来自动生成访问者类?

std::enable_ifboost::mpl::find似乎是要走的路,但我不能模板化虚拟方法,不是吗?

不能使用可变参数模板虚拟方法,但可以模板化基类:

template<class T> class singleVisitorBase { virtual void visit(T) = 0; };
template<class list> class visitor;
template<class... Ts> class visitor<boost::mpl::list<Ts...>>
    : singleVisitorBase<Ts>... {};

另一种方法是使用递归继承:

template<class list> class visitor;
template<> class visitor<boost::mpl::list<>> {};
template<class T, class... Ts> class visitor<boost::mpl::list<T, Ts...>>
    : singleVisitorBase<T>, visitor<boost::mpl::list<Ts...>> {};

但是,我更喜欢单级多重继承,因为它会产生更干净的类型层次结构,这些层次结构更易于在调试器中检查。

在这两种情况下,都会有一些空间开销,因为visitor将包含n vtable 指针到其 vtable,以允许投射到基类型。空间开销较少但编译时开销较大的替代方法是使用 Boost.Preprocessor 通过 BOOST_PP_REPEAT 生成长度n的类体:

template<class list, std::size_t N> class visitorImpl;
#define VISITOR_MAX 32
#define VISITOR_VISIT(z,I,_) 
    virtual void visit(typename boost::mpl::at<list, I>::type) = 0;
#define VISITOR_CLASS(z,N,_) 
template<class list>         
class visitorImpl<list, N>   
{                            
    BOOST_PP_REPEAT(N, VISITOR_VISIT, ) 
};
BOOST_PP_REPEAT(VISITOR_MAX, VISITOR_CLASS, )
template<class list> using visitor
    = visitorImpl<list, typename boost::mpl::size<list>::type::value>;