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