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

时间:2010-07-05 08:44:02

标签: c++ templates

我有不同的类型,比如ABC,它们都是从某个基类Base继承的:

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

我需要一个容器,我们称之为Master,它包含指向ABC类型对象的指针。我希望Master容器在所有包含的Base对象上提供迭代器,并在所有包含的A上提供特定类型的迭代器,{{1} }和B个对象。作为存储后端,我将使用C,但如果以后可以轻松切换它会很好。

从概念上讲,这是std::vector应该向外界展示的界面:

Master

界面不必与此精确语法相匹配。例如,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>()容器,如果我想添加类MasterDE(也继承自F)。最好,我想用一两行代码扩展它。

所有这些都可以用很多Base来实现,但那很难看。我认为模板和多重继承的一些魔力可以帮助我在这里。这堂课最干净的实施是什么?

4 个答案:

答案 0 :(得分:4)

首先你应该看看Boost.Variant 它允许您在容器中存储多个不相关的对象 迭代器本身必须尝试boost::get<T>()为他的类型到达下一个类型为T.的对象 如果对象不是T类型,则向前迭代 如果你想迭代所有对象,只需返回这些对象的变体,那么A,B和C不必与Base相关,如果你不需要它们,或者只是指向Base的指针,如果所有的用例都是有一个共同的基类。

答案 1 :(得分:4)

这是我将要做的草图:

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

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

derive_from模板看起来像这样:

//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 :(得分:2)

为什么不RTTI + boost filter_iterator?人们通常害怕RTTI,但是带有模板过滤器的filter_iterator比较两个type_infos就好了。

答案 3 :(得分:0)

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

如何避免界面中的“冗余”?

主类有一些似乎多余的功能(a_begin / a_endb_begin / b_end对比{{1} } / c_begin)。我的第一个建议是在这种情况下使用Java样式的迭代器,以便将c_end函数从end的接口移到相应的迭代器中。

考虑这个例子:

master

这样,每个具体类型只有一个迭代器getter(master *m = ..; master::iterator<A*> a = m->getA(): while ( a->hasNext() ) { A *current = a->next(); current->doSomething() } AB)。

我怀疑通过一些思考,迭代器getter可能是一个成员模板,因此你只有一个get()模板,并且可以说C。出于性能原因,我想专门针对那些获取器来迭代特定容器(见下文),我想。

如何使迭代器有效迭代?

m->get<A>()迭代器应迭代所有包含的对象,具体的迭代器应该只迭代所包含对象的子集。这样做,我建议让Base包含多个 master个对象,每个具体类型一个。

然后,您的std::vector迭代器可以迭代包含所有A的向量,对于其他具体类型也是如此。 A*迭代器将简单地迭代所有容器,将它们视为一个连续容器。