假设我想实现我自己的集合类型,如下所示:
#define ARR_SIZE 20
class IntegersCollection {
public:
class Iterator {
public:
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = int;
using pointer = value_type *;
using reference = value_type &;
Iterator(pointer ptr) : m_ptr(ptr) {}
reference operator*() const { return *m_ptr; }
pointer operator->() { return m_ptr; }
Iterator &operator++() {
m_ptr++;
return *this;
}
Iterator operator++(int) {
Iterator tmp = *this;
++(*this);
return tmp;
}
friend bool operator==(const Iterator &a, const Iterator &b) {
return a.m_ptr == b.m_ptr;
};
friend bool operator!=(const Iterator &a, const Iterator &b) {
return a.m_ptr != b.m_ptr;
};
private:
pointer m_ptr;
};
Iterator begin() { return Iterator(&m_data[0]); }
Iterator end() { return Iterator(&m_data[ARR_SIZE]); }
private:
int m_data[ARR_SIZE];
};
问题是,用户可以通过多种方式将集合类型/容器类型与迭代器一起使用。我不确定我是否已经实现了完整且正确的迭代器所需的所有所需成员方法/字段。
C++20 引入了 Concept 特性,并且有一些与迭代器相关的概念,例如 this 。我在想:
是否有类似“迭代器概念”的东西,它清楚地定义了特定类型的迭代器(例如前向迭代器)应该具有哪些成员方法/字段?我正在想象如下的事情:
template <typename T>
concept is_shape = requires(T v) {
{ v.area() } -> std::floating_point;
};
class Circle {
private:
double r;
public:
Circle(double r) { this->r = r; }
double area() { return r * r * std::numbers::pi_v<float>; };
};
template <is_shape T> float getVolume(T &shape, float height) {
return shape.area() * height;
}
Circle my_circle(3);
std::cout << getVolume(my_circle, 7.2) << "\n";
我们可以有一个
is_shape
概念来规定所有“形状”的行为,我们是否有迭代器的东西,这样如果我错过了一些方法/字段,C++ 可以立即让我失败,而不是将失败延迟到而后来,当真正的用户以特定方式使用我的迭代器并发现我的迭代器实际上错过了一些重要功能时?
有没有类似“迭代器概念”的东西
std::random_access_iterator
,所以想必您知道答案是肯定的。
std::bidirectional_iterator
...,它本身精炼std::forward_iterator
...,这又精炼std::input_iterator
,这......等等
...这样,如果我错过了一些方法/字段,C++ 可以立即让我失败,而不是将失败推迟到稍后,当真正的用户以特定方式使用我的迭代器并发现我的迭代器实际上错过了一些重要特征?
您实际上还没有说出您打算支持哪些功能。也就是说,我不知道您是否打算实现一个随机访问迭代器(缺少
operator[]
),或者双向迭代器(缺少 operator--
),或者什么。
一旦选择了想要实现的迭代器概念,只需编写例如即可。
static_assert(std::random_access_iterator<Iterator>);
(如评论中所述)就足够了。
如果静态断言失败,你就会得到答案:你还没有正确实现这个概念。现在您需要阅读错误消息,告诉您原因。
例如,如果编译器告诉你它不满足
concept semiregular = copyable<_Tp> && default_initializable<_Tp>;
^
这显然意味着您需要添加默认构造函数(或现有构造函数参数的默认值)。
这是因为
forward_iterator
需要 incrementable
需要 regular
需要 semiregular
需要 default_initializable
- 所有这些都在错误消息和您已经链接的文档中进行了描述.