如何用sentinel编写可迭代类以在find_if中使用它?

问题描述 投票:0回答:1

我在 2023 年 3 月左右编写了 C++ 代码。当时编译得很好。现在,我必须对其进行一些更改,但它不再编译。使用的语言标准是C++20。我不记得当时用的什么版本的VS。那肯定已经更新到最新的了。

现在我在调用时收到“错误 C3889:调用类类型 'std::ranges::_Find_if_fn' 的对象:找不到匹配的调用运算符”错误

ranges::find_if(network_list, [](auto const& item) { return item.IsConnected(); })

然后它说“‘std::ranges::borrowed_iterator_t’:不满足相关约束”,然后“概念‘std::ranges::range’评估为 false”。目前还不清楚发生了什么。

我最好的猜测是 find_if 变得更严格,但我不明白到底是怎么回事。 network_list 是具有 begin 和 end 方法的可迭代的自定义实现的实例。 end 方法返回一个哨兵类。我想问题与此有关,因为如果我将调用更改为

ranges::find_if(network_list.begin(), network_list.end(), [](auto const& item) { return item.IsConnected(); })

我得到了一个不同的错误,但它在某种程度上是有道理的。它说“概念‘std::sentinel_for’评估为 false”,然后“概念‘std::_Weakly_equality_comparable_with’评估为 false”,然后“概念‘std::_Half_equality_comparable’评估为 false”。

可能我对该迭代的实现和哨兵类的使用不遵循特定规则,但我找不到如何实现它们以使 find_if 等函数正常工作的示例。谁能举出正确的例子吗?

更新:

回答有关network_list类型的问题。我认为声明它是 iterable 的自定义实现就足够了。在这里

template<class T>
class IterableAsync final {
   friend class YieldPromise<T>;
   friend class IteratorAsync<T>;

   using handle_type = std::coroutine_handle<YieldPromise<T>>;

private:
   handle_type m_objHandle;

public:
   // promise_type is expected by STL to be publicly declared
   using promise_type = YieldPromise<T>;

private:
   explicit IterableAsync(handle_type objHandle) : m_objHandle(std::move(objHandle)) {
   }

public:
   IterableAsync(IterableAsync const& other) = delete;

   IterableAsync(IterableAsync&& other) noexcept :
      m_objHandle(other.m_objHandle) {
      other.m_objHandle = nullptr;
   }

   ~IterableAsync() {
      if(m_objHandle) {
         m_objHandle.destroy();
      }
   }

public:
   IteratorAsync<T> begin() {
      return IteratorAsync<T>(*this, false);
   }

   // ReSharper disable once CppMemberFunctionMayBeStatic
   IteratorAsyncSentinel end() {
      return IteratorAsyncSentinel();
   }

public:
   IterableAsync& operator =(IterableAsync const& other) = delete;

   IterableAsync& operator =(IterableAsync&& other) noexcept {
      m_objHandle = other.m_objHandle;
      other.m_objHandle = nullptr;
      return *this;
   }
};

更新2:

我有点希望有人能提供一个关于如何正确编写可交互/迭代器/哨兵的标准的链接,或者在此处发布该示例,而不是分析我的代码中的缺失,这可能会更困难,但如果这更容易,这里是另一个需要的零件

 class IteratorAsyncSentinel final {};

template<class T>
class IterableAsync;

template<class T>
class IteratorAsync final {
   friend class IterableAsync<T>;

public:
   // difference_type and value_type are expected by ranges
   using difference_type = ptrdiff_t;
   using value_type = T;

private:
   std::reference_wrapper<IterableAsync<T>> m_objIterable;
   bool m_bIsDone;

private:
   IteratorAsync(IterableAsync<T>& objIterable, bool bIsDone) :
      m_objIterable(objIterable),
      m_bIsDone(bIsDone) {
      if(!m_bIsDone) {
         Advance();
      }
   }

public:
   IteratorAsync() :
      m_objIterable(*reinterpret_cast<IterableAsync<T>*>(nullptr)),
      m_bIsDone(false) {
   }
   IteratorAsync(IteratorAsync const& other) = default;
   IteratorAsync(IteratorAsync&& other) noexcept = default;
   ~IteratorAsync() = default;

public:
   bool operator !=(IteratorAsyncSentinel const&) const {
      return !m_bIsDone;
   }

   bool operator ==(IteratorAsyncSentinel const&) const {
      return m_bIsDone;
   }

   IteratorAsync& operator ++() {
      Advance();
      return *this;
   }

   IteratorAsync operator ++(int) {
      IteratorAsync objPrevIterator = *this;
      Advance();
      return objPrevIterator;
   }

   T const& operator *() const {
      return m_objIterable.get().m_objHandle.promise().Current();
   }

private:
   void Advance() {
      m_objIterable.get().m_objHandle.resume();
      m_bIsDone = m_objIterable.get().m_objHandle.done();
   }

public:
   IteratorAsync& operator =(IteratorAsync const& other) = default;
   IteratorAsync& operator =(IteratorAsync&& other) noexcept = default;
};
c++ stl iterable sentinel
1个回答
-1
投票

谢谢你的提示。事实证明,哨兵类型的实现现在需要实现相等运算符。正如我一年前提到的,为什么不需要它仍然是一个谜。对我来说,哨兵只是迭代结束的“标记”。迭代器上肯定需要相等运算符,但哨兵上不需要,并且哨兵上的需要使事情变得复杂。只要我原来的问题得到解决,我就会发布这个答案,但如果有人可以阐明这些新要求,特别是如果可以删除该要求,那就太好了。

© www.soinside.com 2019 - 2024. All rights reserved.