使用 C++20 概念为自定义容器创建迭代器

Creating an Iterator with C++20 Concepts for custom container

C++20 introduces concepts, a smart way to put constraints on the types a template function or class can take in.

While iterator categories and properties remain the same, what changes is how you enforce them: with tags until C++17, with concepts since C++20. For example, instead of the std::forward_iterator_tag tag you would mark your iterator with the std::forward_iterator concept.

The same thing applies to all iterator properties. For example, a Forward Iterator must be std::incrementable. This new mechanism helps in getting better iterator definitions and makes errors from the compiler much more readable.

这段文字摘自这篇文章: https://www.internalpointers.com/post/writing-custom-iterators-modern-cpp

但是作者并没有升级关于如何在C++20上制作自定义迭代器的概念,它仍然是<= C++17标签版本。

谁能举例说明如何在具有概念功能的 C++20 版本中为自定义容器编写自定义迭代器?

总的来说,C++20 定义迭代器的方式取消了显式标记类型,而是依赖概念来检查给定类型是否恰好符合迭代器类别的要求。

这意味着您现在可以安全地 duck-type 获得胜利,同时支持干净的重载解决方案和错误消息:

struct my_iterator {
  // No need for tagging or anything special, just implement the required interface.
};

如果要确保给定类型满足特定迭代器类别的要求,您static_assert该类型的概念:

#include <iterator>

static_assert(std::forward_iterator<my_iterator>);

强制一个函数只接受特定的迭代器类别是通过在你的模板参数中使用这个概念来完成的。

#include <iterator>

template<std::forward_iterator Ite, std::sentinel_for<Ite> Sen>
void my_algorithm(Ite begin, Sen end) {
 // ...
}

std::sentinel_for<> 现在用于结束迭代器,而不是两次使用 Ite。它允许有选择地为结束迭代器使用单独的类型,这有时很方便,尤其是对于输入迭代器。

例如:

struct end_of_stream_t {};
constexpr end_of_stream_t end_of_stream{};

struct my_input_iterator {
  // N.B. Not a complete implementation, just demonstrating sentinels.
  some_stream_type* data_stream;

  bool operator==(end_of_stream_t) const { return data_stream->empty(); }
};

template<std::input_iterator Ite, std::sentinel_for<Ite> Sen>
void my_algorithm(Ite begin, Sen end) {
  while(begin != end) {
    //...
  }
}

void foo(some_stream_type& stream) {
  my_algorithm(my_input_iterator{&stream}, end_of_stream);
}