我创建了一个集合,我想提供一个STL风格的随机访问迭代器.我正在寻找迭代器的示例实现,但我没有找到任何.我知道需要const重载[]和*运算符.迭代器有什么要求是"STL风格",还有哪些其他缺陷需要避免(如果有的话)?
附加上下文:这是一个库,除非我真的需要,否则我不想引入任何依赖.我编写自己的集合,以便能够使用相同的编译器在C++ 03和C++ 11之间提供二进制兼容性(因此没有STL可能会破坏).
3月21 日,标准委员会投票赞成批准P0174中std::iterator提议的弃用:
对于读者而言,很长的void参数序列不仅仅是简单地
typedef在类定义本身中提供预期的s,这是当前工作草案采用的方法,遵循c ++中设置的模式14
在c ++ 17之前std::iterator,鼓励继承从迭代器样板实现中删除乏味.但弃用将需要以下其中一项:
typedefsauto而不是依赖于迭代器来声明类型std::iterator_traits,可以更新,而继承工作std::iterator有人可以告诉我我应该期待哪些选项,因为我设计了自定义迭代器,着眼于c ++ 17兼容性?
我正在实现一个具有STL类接口的自定义容器.我必须提供一个常规迭代器和一个const迭代器.两个版本的迭代器的大多数代码都是相同的.我怎样才能避免这种重复?
例如,我的容器类是Foo,我正在实现FooIterator和FooConstIterator.两个迭代器都必须提供operator++()相同的方法.
我的问题类似于如何删除类似的const和非const成员函数之间的代码重复?但是那个问题的答案特定于const和非const方法,尤其是访问器.我没有看到这可能会如何推广到迭代器问题.
我应该FooIterator从FooConstIterator其他非const方法派生并扩展它吗?这要么导致虚拟方法或方法隐藏,这在这里似乎不合适.
也许FooIterator应该包含一个FooConstIterator.虽然这种方法确实减少了实现重复,但它似乎重新引入了许多样板方法定义.
是否有聪明的模板技术从单个定义生成两个迭代器?或许有一种方法 - 颤抖 - 使用预处理器来消除这些几乎相同的类.
我已经尝试查看我的本地STL实现,看看它是如何处理它的.有很多辅助类,我在设计中遇到了麻烦,但看起来功能很简单.
在以前的项目中,我的自定义容器是在标准STL容器之上构建的,所以我不必提供自己的迭代器.在这种情况下,这不是一个选项.
在关于迭代器的另一个问题之后,我对自定义容器有一些疑问.在我的容器中,iterator是一个子类const_iterator,所以我从非const转换为const"免费".但这是允许的,还是有这样的设置有任何缺点或非工作方案?
作为开发人员团队的一员,我想确保在我们发布的自定义迭代器上实现一组函数(和运算符).使用STL迭代器类型作为基本类型有帮助,但是由于某些原因(在我的控制范围之外),我们决定不强制执行STL兼容性.迭代器由同一团队和整个公司的人员使用.
我想设计一个消耗迭代器类型的模板类,并根据设计合同进行测试.
例如,我希望迭代器实现一个operator ++,operator--并声明所需的typedef.
1>是否可以实现强制设计合同的模板类?可能使用static_assert?
2>如果是,这是一个好的设计吗?
reference:自定义迭代器
假设我们有一个普通数组(或其他支持基于范围的循环的容器):
const int N = 8;
int arr[N] = {0, 1, 2, 3, 4, 5, 6, 7};
Run Code Online (Sandbox Code Playgroud)
使用索引或迭代器,我们可以遍历奇数元素,将索引增加2:
for (int i = 0; i < N; i+=2)
{
std::cout << arr[i] << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
如何使用基于范围的循环获得类似的结果并避免显式迭代器/索引或迭代跳过使用?就像是:
for (const auto& v: odd_only(arr))
{
std::cout << v << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
您看到的简单而优雅的解决方案是什么?标准库是否包含类似的内容?
我有一些类通常使用标准容器作为底层字段.例如,我有一个班级
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 …Run Code Online (Sandbox Code Playgroud) 在实现自定义容器时,我到了需要实现迭代器的地步。当然,我不想为const和non-const迭代器编写两次代码。我发现了这个问题,详细说明了这样的可能实现:
template<class T>
class ContainerIterator {
using pointer = T*;
using reference = T&;
...
};
template<class T>
class Container {
using iterator_type = ContainerIterator<T>;
using const_iterator_type = ContainerIterator<const T>;
}
Run Code Online (Sandbox Code Playgroud)
但是,我也发现了这个这个问题,使用模板参数:
template<class T, bool IsConst>
class ContainerIterator {
using pointer = std::conditional_t<IsConst, const T*, T*>;
using reference = std::conditional_t<IsConst, const T&, T&>;
...
};
template<class T>
class Container {
using iterator_type = ContainerIterator<T, false>;
using const_iterator_type = ContainerIterator<T, true>;
}
Run Code Online (Sandbox Code Playgroud)
第一个解决方案似乎更容易,但是答案是从2010年开始。经过一些研究,似乎第一个版本并未得到广泛使用,但我不知道为什么。我觉得我缺少第一个版本的一些明显缺陷。
因此问题变为:
第一个版本有什么问题吗?
如果没有,为什么版本#2似乎是c ++ …
我想弄清楚这里有几件事:
如何为下面的类实现迭代器?
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
class Node {
public:
Node(int i=0):val(i) {}
Node*& operator++(int i=0) {return next;};
T val;
Node *next;
};
//================================================
int main() {
Node<int> *head, *tmp1, *tmp2;
tmp1 = new Node<int>(0);
head = tmp1;
for (int i=1; i<10; ++i) {
tmp2 = new Node<int>(i);
tmp1->next = tmp2;
tmp1 = tmp2;
}
while (head != NULL) {
cout << head->val << " '";
head = head->operator++(0); //How do I make …Run Code Online (Sandbox Code Playgroud)我找到了这个老答案.我想知道解决方案是否仍然有效,或者是否有更新,更有效的方法.
让我们假设我有一个像下面这样的迭代器(细节并不重要,只是它很大):
class inorder_iterator : public std::iterator<std::forward_iterator_tag, token>
{
friend syntax_tree;
node* current_node;
std::stack<node*> prev_nodes;
//std::stack<node*> visited_nodes;
std::map<node*, bool> visited;
public:
inorder_iterator();
inorder_iterator& operator++();
inorder_iterator operator++(int);
token& operator*();
const token& operator*() const;
token* operator->();
const token* operator->() const;
friend bool operator==(const inorder_iterator lhs, const inorder_iterator rhs);
friend bool operator!=(const inorder_iterator lhs, const inorder_iterator rhs);
private:
inorder_iterator(node* current);
node* find_leftmost_node(node* from);
};
Run Code Online (Sandbox Code Playgroud)
成员函数声明的实现具有合理的大小,但我想重用当前的迭代器来减少代码重复.
想到的第一个想法就是在node类型上进行模板化,所以我可以通过const node使它成为const迭代器,但它听起来很腥
template <typename Node>
//replace every occurrence …Run Code Online (Sandbox Code Playgroud) c++ ×10
iterator ×7
c++11 ×2
c++17 ×2
c++14 ×1
casting ×1
code-reuse ×1
const ×1
containers ×1
deprecated ×1
dry ×1
linked-list ×1
standards ×1