【问题标题】:Can I build an abstract visitor using a typelist?我可以使用类型列表构建抽象访问者吗?
【发布时间】:2015-06-03 10:37:01
【问题描述】:

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

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_if 和 boost::mpl::find 似乎是要走的路,但我不能模板虚拟方法可以吗?

【问题讨论】:

    标签: c++ boost


    【解决方案1】:

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

    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 将在其 vtable 中包含 n vtable 指针,以允许强制转换为基本类型。另一种空间开销较小但编译时间开销较大的方法是使用 Boost.Preprocessor 通过BOOST_PP_REPEAT 生成n-length 类体:

    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>;
    

    【讨论】:

    • 继承的性能损失是线性的还是恒定的?就像一个班级有 20 多个父母的想法有点吓人
    • @SamKellett 在典型的实现中应该是常数,尽管会有一些空间开销(20+ vtable 指针指向同一个 vtable);见tinydrblog.appspot.com/?p=89001
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-20
    • 2010-09-21
    • 1970-01-01
    相关资源
    最近更新 更多