C++20 对 std::contiguous_iterator_tag
有明确的库支持.一些 STL 算法(例如 std::copy
)可以在连续迭代器上表现得更好。但是,我不清楚程序员应该如何访问这个新功能。
为了论证起见,让我们假设我们有一个完全符合 C++20 的库实现。我想编写最简单的连续迭代器。
Here's my first attempt.
#include <iterator>
class MyIterator {
int *p_;
public:
using value_type = int;
using reference = int&;
using pointer = int*;
using difference_type = int;
using iterator_category = std::contiguous_iterator_tag;
int *operator->() const;
int& operator*() const;
int& operator[](int) const;
MyIterator& operator++();
MyIterator operator++(int);
MyIterator& operator--();
MyIterator operator--(int);
MyIterator& operator+=(int);
MyIterator& operator-=(int);
friend auto operator<=>(MyIterator, MyIterator) = default;
friend int operator-(MyIterator, MyIterator);
friend MyIterator operator+(MyIterator, int);
friend MyIterator operator-(MyIterator, int);
friend MyIterator operator+(int, MyIterator);
};
namespace std {
int *to_address(MyIterator it) {
return it.operator->();
}
}
static_assert(std::contiguous_iterator<MyIterator>); // FAILS
这在 GCC/libstdc++ 和 MSVC/STL 上都失败了;但它应该吗?对于我的下一次尝试,我专门
pointer_traits<MyIterator>
. MyIterator
实际上不是指针,所以我没有在 pointer_traits
中放入任何东西除了图书馆需要的一个功能。 This is my second attempt :#include <iterator>
class MyIterator {
~~~
};
template<>
struct std::pointer_traits<MyIterator> {
int *to_address(MyIterator it) {
return it.operator->();
}
};
static_assert(std::contiguous_iterator<MyIterator>); // OK!
这是我应该做的吗?感觉非常hacky。 (需要明确的是:我的第一次失败尝试也感觉非常糟糕。)我错过了一些更简单的方法吗?
特别是,
MyIterator
有什么办法吗?本身来保证它是连续的,只使用成员和 friend 以及可以在类的主体中定义的东西?就像,如果 MyIterator
定义在某个深度嵌套的命名空间中,我不想为了打开 namespace std
而一路突破到顶级命名空间.编辑添加:Glen Fernandes 告诉我有一个更简单的方法——我应该添加一个
element_type
类型定义,like this! (而且我可以在 C++20 中删除 iterator_traits
' 大 5 个 typedef 中的 3 个。)这看起来更好!#include <iterator>
class MyIterator {
int *p_;
public:
using value_type = int;
using element_type = int;
using iterator_category = std::contiguous_iterator_tag;
int *operator->() const;
int& operator*() const;
int& operator[](int) const;
MyIterator& operator++();
MyIterator operator++(int);
MyIterator& operator--();
MyIterator operator--(int);
MyIterator& operator+=(int);
MyIterator& operator-=(int);
friend auto operator<=>(MyIterator, MyIterator) = default;
friend int operator-(MyIterator, MyIterator);
friend MyIterator operator+(MyIterator, int);
friend MyIterator operator-(MyIterator, int);
friend MyIterator operator+(int, MyIterator);
};
static_assert(std::contiguous_iterator<MyIterator>); // OK!
另外,我看到了一些关于使用成员 typedef
iterator_concept
的内容。而不是 iterator_category
.我为什么要提供 MyIterator::iterator_concept
? (我不是在这里要求完整的历史解释;只是一个简单的最佳实践指南“不要忘记 iterator_concept
”或“是的,因为它有助于 X”会很好。)
最佳答案
C++ 概念作为语言特性的主要好处之一是概念定义告诉您需要提供什么。 std::contiguous_iterator
is no different .是的,您可能需要深入研究 10 多个其他概念定义层才能深入了解您需要提供的基本术语。但它们就在语言中。
简而言之,连续迭代器是随机访问迭代器:
contiguous_iterator
reference_type
是对其 value_type
的左值引用(即:不是代理迭代器或生成器)。 std::to_address
可以被调用以将任何有效的迭代器(即使是不可解引用的)转换为指向迭代器引用的元素或指向最后一个指针的指针。 不幸的是,满足 #3 不能通过特化来完成
std::to_address
直接地。您必须使用专业 pointer_traits::to_address
为您的迭代器类型或给您的迭代器一个 operator->
重载。后者更容易做到,尽管
operator->
std::contiguous_iterator
没有其他要求, 对于这样的迭代器类型是有意义的:class MyIterator
{
...
int const *operator->() const;
};
仅供引用:如果您基于概念约束模板,而不仅仅是 static_assert
,大多数编译器会给您更多有用的错误消息。正在研究它。像这样:template<std::contiguous_iterator T>
void test(const T &t);
test(MyIterator{});
关于c++ - 在 C++20 中,如何编写连续迭代器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65712091/