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

Ale*_*ara 19 c++ c++-concepts c++20

C++20 引入了概念,这是一种对模板函数或类可以采用的类型施加约束的智能方法。

虽然迭代器类别和属性保持不变,但改变的是执行它们的方式:C++17 之前使用标记,C++20 以来使用概念。例如,您可以使用 std::forward_iterator 概念来标记迭代器,而不是使用 std::forward_iterator_tag 标签。

同样的事情也适用于所有迭代器属性。例如,前向迭代器必须是 std::incrementable。这种新机制有助于获得更好的迭代器定义,并使编译器中的错误更具可读性。

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

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

有人可以举例说明如何使用概念功能在 C++20 版本中为自定义容器编写自定义迭代器吗?

小智 12

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

这意味着您现在可以安全地通过鸭子类型获得胜利,同时支持干净的重载解析和错误消息:

struct my_iterator {
  // No need for tagging or anything special, just implement the required interface.
};
Run Code Online (Sandbox Code Playgroud)

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

#include <iterator>

static_assert(std::forward_iterator<my_iterator>);
Run Code Online (Sandbox Code Playgroud)

通过使用模板参数中的概念来强制函数仅接受特定的迭代器类别。

#include <iterator>

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

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);
}
Run Code Online (Sandbox Code Playgroud)