转换迭代器和 const_iterators
Converting iterators and const_iterators
一般背景:
我正在尝试构建一个容器,该容器将作为 运行 时间定义维度的多维数组的包装器 - 事实上,底层数组当然是总大小的一维数组。主要部分是 operator []
returns 子数组上的包装器。
由于容器需要迭代器,我目前正在该容器上实现迭代器,Container::iterator
和 Container::const_iterator
。我努力模仿标准容器迭代器,它们应该尊重随机访问和输出迭代器的所有要求。
我已经注意到以下要求:
- 一个public默认构造函数
- (当然是复制和移动语义)
- 从
iterator
到 const_iterator
的隐式转换
- 迭代器和const_interator应该是可比较的
具体上下文:
标准容器迭代器根本不提供从 const_iterator
到 iterator
的转换,因为删除 constness 可能很危险。我已经在 SO 中搜索了该问题并找到了 How to remove constness of const_iterator?,其中答案提出了不同的技巧来从运算符中删除 constness。所以我现在想知道我是否应该在指针上实现从 const_iterator 到迭代器 ala const_cast
的 explicit 转换。
问题:
实现从 const_iterator
到(非 const)iterator
的显式转换有什么风险,它与链接问题的解决方案有何不同(此处复制以便于阅读):
使用 advance 和 distance(恒定时间来自我的随机访问迭代器)
iter i(d.begin());
advance (i,distance<ConstIter>(i,ci));
正在使用擦除:
template <typename Container, typename ConstIterator>
typename Container::iterator remove_constness(Container& c, ConstIterator it)
{
return c.erase(it, it);
}
作为参考,这里是我的迭代器的简化和部分实现:
// Base for both iterator and const_iterator to ease comparisons
template <class T>
class BaseIterator {
protected:
T *elt; // high simplification here...
BaseIterator(T* elt): elt(elt) {}
virtual ~BaseIterator() {}
public:
bool operator == (const BaseIterator& other) {
return elt == other.elt;
}
bool operator != (const BaseIterator& other) {
return ! operator == (other);
}
// other comparisons omitted...
BaseIterator& add(int n) {
elt += n;
return *this;
}
};
// Iterators<T> in non const iterator, Iterator<T, 1> is const_iterator
template <class T, int cnst=0, class U= typename std::conditional<cnst, const T, T>::type >
class Iterator: public BaseIterator<T> {
using BaseIterator<T>::elt;
public:
using value_type = U;
using reference = U*;
using pointer = U&;
using difference_type = int;
using iterator_category = std::random_access_iterator_tag;
Iterator(): BaseIterator<T>(nullptr);
Iterator(T* elt): BaseIterator<T>(elt) {}
// conversion from iterator to const_iterator
template <class X, typename = typename std::enable_if<
(cnst == 1) && std::is_same<X, T>::value>::type>
Iterator(const BaseIterator<X>& other): BaseIterator<X>(other) {};
// HERE: explicit conversion from const_iterator to non const
template <class X, typename = typename std::enable_if<
std::is_same<X, T>::value && (cnst == 0)>::type>
explicit Iterator(const Iterator<X, 1 - cnst>& other): BaseIterator<T>(other) {}
// partial implementation below
U& operator *() {
return *elt;
}
U* operator ->() {
return elt;
}
Iterator<T, cnst, U>& operator ++() {
this->add(1);
return *this;
}
};
您引用的两种方法都需要对容器进行非常量访问,因此您无法将 const 底层元素作为非常量进行访问。
你说的不是,所以可以是UB [dcl.type.cv]
一般背景:
我正在尝试构建一个容器,该容器将作为 运行 时间定义维度的多维数组的包装器 - 事实上,底层数组当然是总大小的一维数组。主要部分是 operator []
returns 子数组上的包装器。
由于容器需要迭代器,我目前正在该容器上实现迭代器,Container::iterator
和 Container::const_iterator
。我努力模仿标准容器迭代器,它们应该尊重随机访问和输出迭代器的所有要求。
我已经注意到以下要求:
- 一个public默认构造函数
- (当然是复制和移动语义)
- 从
iterator
到const_iterator
的隐式转换
- 迭代器和const_interator应该是可比较的
具体上下文:
标准容器迭代器根本不提供从 const_iterator
到 iterator
的转换,因为删除 constness 可能很危险。我已经在 SO 中搜索了该问题并找到了 How to remove constness of const_iterator?,其中答案提出了不同的技巧来从运算符中删除 constness。所以我现在想知道我是否应该在指针上实现从 const_iterator 到迭代器 ala const_cast
的 explicit 转换。
问题:
实现从 const_iterator
到(非 const)iterator
的显式转换有什么风险,它与链接问题的解决方案有何不同(此处复制以便于阅读):
使用 advance 和 distance(恒定时间来自我的随机访问迭代器)
iter i(d.begin()); advance (i,distance<ConstIter>(i,ci));
正在使用擦除:
template <typename Container, typename ConstIterator> typename Container::iterator remove_constness(Container& c, ConstIterator it) { return c.erase(it, it); }
作为参考,这里是我的迭代器的简化和部分实现:
// Base for both iterator and const_iterator to ease comparisons
template <class T>
class BaseIterator {
protected:
T *elt; // high simplification here...
BaseIterator(T* elt): elt(elt) {}
virtual ~BaseIterator() {}
public:
bool operator == (const BaseIterator& other) {
return elt == other.elt;
}
bool operator != (const BaseIterator& other) {
return ! operator == (other);
}
// other comparisons omitted...
BaseIterator& add(int n) {
elt += n;
return *this;
}
};
// Iterators<T> in non const iterator, Iterator<T, 1> is const_iterator
template <class T, int cnst=0, class U= typename std::conditional<cnst, const T, T>::type >
class Iterator: public BaseIterator<T> {
using BaseIterator<T>::elt;
public:
using value_type = U;
using reference = U*;
using pointer = U&;
using difference_type = int;
using iterator_category = std::random_access_iterator_tag;
Iterator(): BaseIterator<T>(nullptr);
Iterator(T* elt): BaseIterator<T>(elt) {}
// conversion from iterator to const_iterator
template <class X, typename = typename std::enable_if<
(cnst == 1) && std::is_same<X, T>::value>::type>
Iterator(const BaseIterator<X>& other): BaseIterator<X>(other) {};
// HERE: explicit conversion from const_iterator to non const
template <class X, typename = typename std::enable_if<
std::is_same<X, T>::value && (cnst == 0)>::type>
explicit Iterator(const Iterator<X, 1 - cnst>& other): BaseIterator<T>(other) {}
// partial implementation below
U& operator *() {
return *elt;
}
U* operator ->() {
return elt;
}
Iterator<T, cnst, U>& operator ++() {
this->add(1);
return *this;
}
};
您引用的两种方法都需要对容器进行非常量访问,因此您无法将 const 底层元素作为非常量进行访问。
你说的不是,所以可以是UB [dcl.type.cv]