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

xqkwcwgp  于 2023-01-10  发布在  其他
关注(0)|答案(2)|浏览(136)

C20引入了一些概念,这是一种对模板函数或类可以接受的类型进行约束的聪明方法。
虽然迭代器的类别和属性保持不变,但改变的是如何执行它们:标记直到C
17,概念从C20开始。例如,代替std::forward_iterator_tag标记,你可以用std::forward_iterator概念标记你的迭代器。
这同样适用于所有的迭代器属性。例如,前向迭代器必须是std::incrementable。这种新机制有助于获得更好的迭代器定义,并使编译器的错误更具可读性。
这段文字摘自这篇文章:https://www.internalpointers.com/post/writing-custom-iterators-modern-cpp
但是作者并没有升级关于如何在C
20上用概念制作自定义迭代器的内容,它仍然是〈= C17标记版本。
有没有人可以举一个例子来说明如何在C
20版本中使用概念特性为自定义容器编写自定义迭代器?

wr98u20j

wr98u20j1#

总的来说,C++20定义迭代器的方式没有显式地标记类型,而是依赖于概念来检查给定的类型是否符合迭代器类别的要求。
这意味着你现在可以安全地避开你的方式获胜,同时支持干净的重载解决方案和错误消息:

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);
}
ergxz8rk

ergxz8rk2#

把这个放在这里也是为了我将来的利益。
一个最小连续迭代器,当你沿着迭代器树往下走的时候,这个迭代器会变得越来越少,但是如果没有这个迭代器,你就不能有一个连续的

struct Iterator
  {
    using iterator_concept [[maybe_unused]] = std::contiguous_iterator_tag;
    using difference_type = std::ptrdiff_t;
    using value_type = <MY TYPE HERE>;
    using pointer = value_type*;
    using reference = value_type&;

    reference operator*() const
    {
      return *_ptr;
    }
    pointer operator->() const
    {
      return _ptr;
    }

    Iterator& operator++()
    {
      _ptr++;
      return *this;
    }
    Iterator operator++(int)
    {
      Iterator tmp = *this;
      ++(*this);
      return tmp;
    }
    Iterator& operator+=(int i)
    {
      _ptr += i;
      return *this;
    }
    difference_type operator+(const Iterator& other) const
    {
      return _ptr + other._ptr;
    }
    Iterator operator+(const difference_type other) const
    {
      return _ptr + other;
    }
    friend Iterator operator+(const difference_type value,
                              const Iterator&       other)
    {
      return other + value;
    }

    Iterator& operator--()
    {
      _ptr--;
      return *this;
    }
    Iterator operator--(int)
    {
      Iterator tmp = *this;
      --(*this);
      return tmp;
    }
    Iterator& operator-=(int i)
    {
      _ptr -= i;
      return *this;
    }
    difference_type operator-(const Iterator& other) const
    {
      return _ptr - other._ptr;
    }
    Iterator operator-(const difference_type other) const
    {
      return _ptr - other;
    }
    friend Iterator operator-(const difference_type value,
                              const Iterator&       other)
    {
      return other - value;
    }

    reference operator[](difference_type idx) const
    {
      return _ptr[idx];
    }

    auto operator<=>(const Iterator&) const = default;

   private:
    pointer _ptr;
  };

相关问题