Mic*_*hal 7 c++ iterator c++11
我有一些类通常使用标准容器作为底层字段.例如,我有一个班级
template <typename T>
class Vec_3D
{
public:
/* ... */
std::array<T, 3> vec;
/* ... */
};
Run Code Online (Sandbox Code Playgroud)
它只有一个变量vec,其余的只是我在处理矢量时需要的函数.我希望能够使用基于范围的for循环,例如
Vec_3D<double> vec;
for (double val : vec) {/*...*/}
Run Code Online (Sandbox Code Playgroud)
这应该是很容易迭代的std::array<double, 3>.
如何在我的类中实现迭代器,而这又应该调用迭代器std::array<T, 3>?
我从这个问题开始,并尝试在我的类中定义迭代器
typedef std::iterator<std::random_access_iterator_tag, T, ptrdiff_t, T*, T&> iterator;
typedef std::iterator<std::random_access_iterator_tag, const T, ptrdiff_t, const T*, const T&> const_iterator;
inline iterator begin() noexcept { return vec.begin(); }
inline const_iterator cbegin() const noexcept { return vec.cbegin(); }
inline iterator end() noexcept { return vec.end(); }
inline const_iterator cend() const noexcept { return vec.end(); }
Run Code Online (Sandbox Code Playgroud)
但得到了编译错误
error: no match for ‘operator!=’ (operand types are ‘Vec_3D<double>::iterator {aka std::iterator<std::random_access_iterator_tag, double, long int, double*, double&>}’ and ‘Vec_3D<double>::iterator {aka std::iterator<std::random_access_iterator_tag, double, long int, double*, double&>}’)
Run Code Online (Sandbox Code Playgroud)
和 operator++, operator*
Yak*_*ont 12
std::iterator是(是)一个帮助器类型来定义typedef典型迭代器所需的s.类中的这些typedef反过来使std::iterator_traits你的迭代器工作.
但是,它实际上并没有为您实现所需的操作.
它已被弃用,因为std委员会不喜欢指定标准迭代器必须具有那些typedef,并且编写typedef并不比确定传递给std::iterator模板的参数要大得多.
这里最简单的方法就是窃取你的底层容器的迭代器.这会使您的抽象泄漏,但它是高效和简单的.
template <typename T>
struct Vec_3D {
using container=std::array<T, 3>;
using iterator=typename container::iterator;
using const_iterator=typename container::const_iterator;
iterator begin() { return vec.begin(); }
iterator end() { return vec.end(); }
const_iterator begin() const { return vec.begin(); }
const_iterator end() const { return vec.end(); }
private:
/* ... */
container vec;
/* ... */
};
Run Code Online (Sandbox Code Playgroud)
如果您不想公开您的基础容器类型,如果您愿意保证您的基础容器是连续的缓冲区,您可以执行以下操作:
template <typename T>
struct Vec_3D {
using iterator=T*;
using const_iterator=T const*;
iterator begin() { return vec.data(); }
iterator end() { return vec.data()+vec.size(); }
const_iterator begin() const { return vec.data(); }
const_iterator end() const { return vec.data()+vec.size(); }
private:
/* ... */
std::array<T,3> vec;
/* ... */
};
Run Code Online (Sandbox Code Playgroud)
因为指针是有效的迭代器.
如果你发现你写的这个"我是一个修改过的容器"样板太多了,你可以自动化它:
template<class Container>
struct container_wrapper {
using container=Container;
using iterator=typename container::iterator;
using const_iterator=typename container::const_iterator;
iterator begin() { return m_data.begin(); }
iterator end() { return m_data.end(); }
const_iterator begin() const { return m_data.begin(); }
const_iterator end() const { return m_data.end(); }
protected:
Container m_data;
};
Run Code Online (Sandbox Code Playgroud)
然后
template <typename T>
class Vec_3D:private container_wrapper<std::array<T,3>> {
// ...
};
Run Code Online (Sandbox Code Playgroud)
但即使这可能有点多,为什么不只是:
template <typename T>
class Vec_3D:public std::array<T,3> {
// ...
};
Run Code Online (Sandbox Code Playgroud)
确实,Vec_3D通过指向base的指针删除是未定义的行为,但谁删除了指向标准容器的指针?
如果这让你担心:
template <typename T>
class Vec_3D: private std::array<T,3> {
using container = std::array<T,3>;
using container::begin();
using container::end();
// ...
};
Run Code Online (Sandbox Code Playgroud)
允许您私下继承,然后将某些操作带回范围.
基于范围的for循环只需要你的类有begin()和end()方法(或过载std::begin(),并std::end()返回迭代器).它并不关心迭代器的来源.因此,最简单的解决方案是使用数组自己的迭代器而不是尝试定义自己的迭代器,例如:
template <typename T>
class Vec_3D
{
public:
typedef typename std::array<T, 3> array_type;
typedef typename array_type::iterator iterator;
typedef typename array_type::const_iterator const_iterator;
// or:
// using array_type = std::array<T, 3>;
// using iterator = array_type::iterator;
// using const_iterator = array_type::const_iterator;
...
inline iterator begin() noexcept { return vec.begin(); }
inline const_iterator cbegin() const noexcept { return vec.cbegin(); }
inline iterator end() noexcept { return vec.end(); }
inline const_iterator cend() const noexcept { return vec.cend(); }
...
private:
array_type vec;
};
Run Code Online (Sandbox Code Playgroud)
std::iterator 只是一个基类,它基本上是一些特征的容器,但如果你想用它来实现你自己的迭代器类,你需要从中派生。
但是你不需要使用它,有一个建议弃用它,你可以直接在你编写的迭代器中定义这些特征。以下问题包含有关提案的信息并有助于实现迭代器类:- 不推荐使用 std::iterator 的准备
目前,您正在使用该基定义容器的迭代器类型,而不是实际上可以进行任何迭代的类,这就是它失败的原因。
您将数组公开为公共成员。如果您很高兴公开您的 vec_3d 是使用数组实现的(无论您是否继续公开公开成员数组),那么您可以只使用数组的迭代器 - 从问题中不清楚您的迭代器需要任何定制行为只是因为您的容器添加了一些功能。
| 归档时间: |
|
| 查看次数: |
9073 次 |
| 最近记录: |