代码之家  ›  专栏  ›  技术社区  ›  Thomas

这个类型化容器的容器最干净的实现是什么?

  •  3
  • Thomas  · 技术社区  · 14 年前

    比如说,我有不同的类型 A , B , C Base

    class Base { ... };
    class A : public Base { ... };
    class B : public Base { ... };
    class C : public Base { ... };
    

    我需要一个容器,我们叫它吧 Master ,它保存指向类型为的对象的指针 A , B C . 我想要那个 硕士 提供迭代器的容器 全部的 底座 A , C 物体。作为存储后端,我将使用 std::vector

    从概念上讲,这是 硕士 应向外界展示:

    class Master {
    
      public:
    
        add(A *a);
        add(B *b);
        add(C *c);
    
        remove(Base *base);
    
        iterator<A*> a_begin();
        iterator<A*> a_end();
        iterator<B*> b_begin();
        iterator<B*> b_end();
        iterator<C*> c_begin();
        iterator<C*> c_end();
        iterator<Base*> base_begin();
        iterator<Base*> base_end();
        // also: reverse iterators, const iterators, reverse const iterators
    };
    

    接口不必与此精确语法匹配。 例如, someMaster.begin<A>() 也很好。

    如果我想添加类的话,以后可以很容易地使用容器 D E F

    dynamic_cast 但那太难看了。我想一些模板和多重继承的魔法可以帮我。这个类最干净的实现是什么?

    4 回复  |  直到 14 年前
        1
  •  4
  •   sbi    14 年前

    下面是我将要做的一个草图:

    // Beware, brain-compiled code ahead
    template< typename T >
    class typed_container
    {
      typedef std::vector<T> data_t;
    public:
      typedef data_t::iterator iterator;
      iterator begin() {return data_.begin();}
      iterator end  () {return data_.end();}
    private:
      data_t data_;
    };
    
    typedef my_type_list<A,B,C> types_t;
    
    class master : public derive_from< typed_container, types_t > {
      template< typename T >
      struct traits {
        typedef typename typed_container<T>::iterator iterator;
        iterator begin(typed_container<T>& c) {return c.begin();}
        iterator end  (typed_container<T>& c) {return c.end  ();}
      };
    public:
      template< typename T > 
      typename traits<T>::iterator begin() {return traits<T>::begin(*this);}
      template< typename T > 
      typename traits<T>::iterator end  () {return traits<T>::end  (*this);}
    
      typedef my_assembling_iterator<types_t> iterator;
    
      iterator begin() {return my_assembling_iterator<types_t>.begin(*this);}
      iterator end  () {return my_assembling_iterator<types_t>.end  (*this);}
    };
    

    my_type_list (相当简单), derive_from (不是那么简单,但也不是太难),以及 my_assembling_iterator


    您可以找到一个工作C++ 03类型列表实现 here . 它最多只需要9个模板参数(但很容易扩展),而且您必须编写

    typedef my_type_list<A,B,C>::result_t types_t
    

    但它简单而免费,而且我知道它是有效的(因为我自己也在使用这个库)。

    这个 模板如下所示:

    //Beware, brain-compiled code ahead!
    template< template<typename> class C, class  >
    struct derive_from;
    
    template< template<typename> class C >
    struct derive_from< C, nil > {};
    
    template< template<typename> class C, typename Head, typename Tail >
    struct derive_from< C, my_type_list<Head,Tail> > : public C<Head>
                                                     , public derive_from<C,Tail> {};
    

        2
  •  4
  •   Community Dai    4 年前

    首先你应该看看 Boost.Variant
    它允许您在一个容器中存储多个不相关的对象。
    迭代器自己必须尝试 boost::get<T>() 他的类型到达类型T的下一个对象。

    如果您想迭代所有对象,只需返回这些对象的一个变量,这样,如果您不需要,a、B和C就不必与Base相关;如果所有用例都有一个公共基类,则只需返回一个指向Base的指针。

        3
  •  2
  •   Alexandre C.    14 年前

    为什么不是RTTI+ boost filter_iterator

        4
  •  0
  •   Frerich Raabe    14 年前

    我在这里看到至少两个问题:

    如何避免接口中的“冗余”?

    master类有一些函数 似乎 多余的( a_begin / a_end b_begin / b_end c_begin / c_end ). 我的第一个建议是在这种情况下使用Java风格的迭代器,以便移动 end master 到相应的迭代器中。

    考虑这个例子:

    master *m = ..;
    master::iterator<A*> a = m->getA():
    while ( a->hasNext() ) {
        A *current = a->next();
        current->doSomething()
    }
    

    A , B , C ).

    我怀疑,经过一些思考,迭代器getter可能是一个成员模板,因此您只有一个get()模板,可以 m->get<A>() . 出于性能方面的考虑,我想您应该将这些getter专门化为只遍历特定容器(见下文)。

    如何使迭代器高效地迭代?

    这个 Base 迭代器应该迭代所有包含的对象,具体的迭代器应该只迭代包含的对象的子集。我建议你这样做 包含 倍数 std::vector 对象,每个具体类型一个。

    你的 A* ,其他混凝土类型相同。这个 底座 迭代器只需迭代所有容器,将它们视为一个连续的容器。