gpt4 book ai didi

c++ - 如何在类中实现标准迭代器

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:03:18 25 4
gpt4 key购买 nike

我有一些类通常使用标准容器作为基础字段。比如我有一个类

template <typename T>
class Vec_3D
{
public:
/* ... */
std::array<T, 3> vec;
/* ... */
};

只有一个变量vec其余的只是我在使用 vector 时需要的功能。我希望能够使用基于范围的 for 循环,例如

Vec_3D<double> vec;
for (double val : vec) {/*...*/}

这显然应该遍历 std::array<double, 3> .

如何在我的类中实现迭代器,依次调用 std::array<T, 3> 的迭代器?

我从 this question 开始并尝试将我的类中的迭代器定义为

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(); }

编译出错

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&>}’)

operator++, operator*

最佳答案

std::iterator 是(曾经)是一种辅助类型,用于定义典型迭代器所需的 typedef。类中的这些 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;
/* ... */
};

如果你不想公开你的底层容器类型,如果你愿意保证你的底层容器是一个连续的缓冲区,你可以这样做:

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;
/* ... */
};

因为指针是有效的迭代器。

如果你发现你写的这个“我是一个修改过的容器”样板文件太多了,你可以自动化它:

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;
};

然后

template <typename T>
class Vec_3D:private container_wrapper<std::array<T,3>> {
// ...
};

但即便如此也可能有点多,为什么不只是:

template <typename T>
class Vec_3D:public std::array<T,3> {
// ...
};

的确,通过指向 base 的指针删除 Vec_3D 是未定义的行为,但是谁删除了指向标准容器的指针?

如果这让您担心:

template <typename T>
class Vec_3D: private std::array<T,3> {
using container = std::array<T,3>;
using container::begin();
using container::end();
// ...
};

让您可以私有(private)继承,然后将某些操作带回作用域。

关于c++ - 如何在类中实现标准迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46431762/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com