我正在编写自己的容器类,它也提供了迭代器。可以取消引用这些迭代器并显示原始容器的子范围,同样可以获得迭代器。
目前,我有一个模板迭代器类(使用boost::iterator_facade
)取消引用Collection
("范围")if L!=0
或者如果T&
,则L==0
(已存储的元素)。是否可以将它们组合在一个类中,这样就不需要重复的代码了?
template<typename T, int L>
class CollectionIter : public boost::iterator_facade<
CollectionIter<T,L>, // type it selfe
Collection<T,L-1>, // value type
boost::random_access_traversal_tag,
Collection<T,L-1> > // deref. type
{
public:
CollectionIter(T* ptr, const std::vector<int>& collectionSize_)
: pointer(ptr), collectionSize(collectionSize_) { }
T* element() { return pointer; }
private:
friend class boost::iterator_core_access;
bool equal(const CollectionIter<T,L>& other) const { return pointer==other.pointer; }
auto dereference() const { return Collection<T,L-1>(pointer, collectionSize); }
void increment() { pointer = pointer + stepsize(); }
void decrement() { pointer = pointer - stepsize(); }
void advance(size_t i) { pointer = pointer + i*stepsize(); }
auto distance_to(const CollectionIter<T,L>& other) { return (other.pointer - pointer)/stepsize(); }
int stepsize() { return collectionSize.at(L); }
T* pointer;
const std::vector<int>& collectionSize;
};
/* Groundlevel Collection: deref returns T& */
template<typename T>
class CollectionIter<T,0> : public boost::iterator_facade<
CollectionIter<T,0>,
T,
boost::random_access_traversal_tag >
{
public:
CollectionIter(T* ptr, const std::vector<int>& collectionSize_)
: pointer(ptr), collectionSize(collectionSize_) { assert(stepsize()==1); }
T* element() { return pointer; }
private:
friend class boost::iterator_core_access;
bool equal(const CollectionIter<T,0>& other) const { return pointer==other.pointer; }
T& dereference() const { return *pointer; }
void increment() { pointer = pointer + stepsize(); }
void decrement() { pointer = pointer - stepsize(); }
void advance(size_t i) { pointer = pointer + i*stepsize(); }
auto distance_to(const CollectionIter<T,0>& other) { return (other.pointer - pointer)/stepsize(); }
int stepsize() { return collectionSize.at(0); }
T* pointer;
const std::vector<int>& collectionSize;
};
答案 0 :(得分:1)
我发现CollectionIter
的两个版本只有三个不同之处:
(1)boost::iterator_facade()
继承的类接收不同的参数。您可以使用Johannes Schaub建议的std::conditional
解决此问题;
public std::conditional< (L > 0U),
boost::iterator_facade<
CollectionIter<T, L>,
Collection<T, L-1U>,
boost::random_access_traversal_tag,
Collection<T, L-1U> >,
boost::iterator_facade<
CollectionIter<T, 0U>,
T,
boost::random_access_traversal_tag > >
(2)构造函数中的assert(stepsize()==1);
仅出现在地面(L == 0U
)版本中。您可以将其修改为
assert( (L > 0U) || (stepsize() == 1) );
(3)递归dereference()
方法在地面版本中确实不同。我不是SFINAE的专家,但如果我没错,你可以按如下方式插入
template <int M = L, typename = std::enable_if_t<(M > 0U)>>
auto dereference () const
{ return Collection<T, L-1U>(pointer, collectionSize); }
template <int M = L, typename = std::enable_if_t<(M == 0U)>>
T & dereference () const
{ return *pointer; }
全班成了(对不起:我在L
更改了std::size_t
)
template <typename T, std::size_t L>
class CollectionIter :
public std::conditional< (L > 0U),
boost::iterator_facade<
CollectionIter<T, L>,
Collection<T, L-1U>,
boost::random_access_traversal_tag,
Collection<T, L-1U> >,
boost::iterator_facade<
CollectionIter<T, 0U>,
T,
boost::random_access_traversal_tag > >
{
public:
CollectionIter (T * ptr, const std::vector<int> & collectionSize_)
: pointer(ptr), collectionSize(collectionSize_)
{ assert( (L > 0U) || (stepsize() == 1) ); }
T* element() { return pointer; }
private:
friend class boost::iterator_core_access;
bool equal (const CollectionIter<T, L> & other) const
{ return pointer==other.pointer; }
template <int M = L, typename = std::enable_if_t<(M > 0U)>>
auto dereference () const
{ return Collection<T, L-1U>(pointer, collectionSize); }
template <int M = L, typename = std::enable_if_t<(M == 0U)>>
T & dereference () const
{ return *pointer; }
void increment ()
{ pointer = pointer + stepsize(); }
void decrement()
{ pointer = pointer - stepsize(); }
void advance (size_t i)
{ pointer = pointer + i*stepsize(); }
auto distance_to (const CollectionIter<T, L> & other)
{ return (other.pointer - pointer)/stepsize(); }
int stepsize()
{ return collectionSize.at(L); }
T * pointer;
const std::vector<int> & collectionSize;
};