我有不同的类型,比如A
,B
,C
,它们都是从某个基类Base
继承的:
class Base { ... };
class A : public Base { ... };
class B : public Base { ... };
class C : public Base { ... };
我需要一个容器,我们称之为Master
,它包含指向A
,B
和C
类型对象的指针。我希望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>()
容器,如果我想添加类Master
,D
和E
(也继承自F
)。最好,我想用一两行代码扩展它。
所有这些都可以用很多Base
来实现,但那很难看。我认为模板和多重继承的一些魔力可以帮助我在这里。这堂课最干净的实施是什么?
答案 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_end
与b_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()
}
,A
,B
)。
我怀疑通过一些思考,迭代器getter可能是一个成员模板,因此你只有一个get()模板,并且可以说C
。出于性能原因,我想专门针对那些获取器来迭代特定容器(见下文),我想。
如何使迭代器有效迭代?
m->get<A>()
迭代器应迭代所有包含的对象,具体的迭代器应该只迭代所包含对象的子集。这样做,我建议让Base
包含多个 master
个对象,每个具体类型一个。
然后,您的std::vector
迭代器可以迭代包含所有A
的向量,对于其他具体类型也是如此。 A*
迭代器将简单地迭代所有容器,将它们视为一个连续容器。