You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写适配ranges::find_if的带哨位自定义可迭代类?

自定义异步可迭代容器与迭代器的标准实现

核心概念要求

要适配std::ranges::find_if这类C++20算法,自定义类型必须满足以下标准概念约束:

  • 迭代器需符合std::input_iterator概念
  • 哨位类型需满足std::sentinel_for<迭代器类型>概念
  • 容器需符合std::ranges::input_range概念;若要支持直接传容器的范围版算法,还需满足std::ranges::borrowed_range(确保迭代器不会提前悬垂)

正确实现示例

假设你的NetworkInfo基础结构如下:

struct NetworkInfo {
    bool IsConnected() const {
        // 自定义连接状态判断逻辑
        return true;
    }
    // 其他成员变量/方法
};

1. 自定义输入迭代器IteratorAsync

#include <iterator>
#include <concepts>

class IteratorAsync {
public:
    // 迭代器标准类型别名
    using value_type = NetworkInfo;
    using reference = const NetworkInfo&;
    using pointer = const NetworkInfo*;
    using difference_type = std::ptrdiff_t;
    using iterator_category = std::input_iterator_tag;

    // 默认构造、拷贝、赋值、析构(编译器默认生成即可)
    IteratorAsync() = default;
    IteratorAsync(const IteratorAsync&) = default;
    IteratorAsync& operator=(const IteratorAsync&) = default;
    ~IteratorAsync() = default;

    // 前置递增(输入迭代器必须实现)
    IteratorAsync& operator++() {
        // 迭代器前进逻辑:比如移动到下一个NetworkInfo条目
        ++current_idx;
        return *this;
    }

    // 后置递增(可选,但建议实现以符合标准)
    IteratorAsync operator++(int) {
        auto temp = *this;
        ++*this;
        return temp;
    }

    // 解引用(必须)
    reference operator*() const {
        // 返回当前指向的NetworkInfo常量引用
        return get_current_item();
    }

    // 箭头运算符(可选,方便访问成员)
    pointer operator->() const {
        return &operator*();
    }

    // 与哨位的相等比较(用于满足sentinel_for概念)
    bool operator==(const class IteratorAsyncSentinel& sentinel) const;

private:
    size_t current_idx = 0;
    NetworkInfo get_current_item() const {
        // 实际获取对应索引的NetworkInfo逻辑
        return NetworkInfo{};
    }
};

2. 自定义哨位IteratorAsyncSentinel

class IteratorAsyncSentinel {
public:
    IteratorAsyncSentinel() = default;

    // 与迭代器的相等比较(双向实现,满足sentinel_for对称性要求)
    bool operator==(const IteratorAsync& iter) const {
        // 判断迭代器是否到达末尾的逻辑:比如索引超出总条目数
        return iter.current_idx >= get_total_count();
    }

    // 反向比较(友元函数实现对称性)
    friend bool operator==(const IteratorAsync& iter, const IteratorAsyncSentinel& sentinel) {
        return sentinel == iter;
    }

private:
    size_t get_total_count() const {
        // 返回网络列表的总条目数
        return 5;
    }
};

// 补全迭代器类中的==运算符实现
bool IteratorAsync::operator==(const IteratorAsyncSentinel& sentinel) const {
    return sentinel == *this;
}

3. 自定义可迭代容器IterableAsync

#include <ranges>

class IterableAsync {
public:
    IteratorAsync begin() const {
        return IteratorAsync{};
    }

    IteratorAsyncSentinel end() const {
        return IteratorAsyncSentinel{};
    }
};

// 特化enable_borrowed_range,告知标准库该容器的迭代器不会在容器存活期间悬垂
template<>
inline constexpr bool std::ranges::enable_borrowed_range<IterableAsync> = true;

验证使用

现在两种形式的std::ranges::find_if都可以正常编译:

#include <algorithm>

int main() {
    IterableAsync network_list;

    // 范围版本调用
    auto it1 = std::ranges::find_if(network_list, [](const NetworkInfo& item) {
        return item.IsConnected();
    });

    // 迭代器对版本调用
    auto it2 = std::ranges::find_if(network_list.begin(), network_list.end(), [](const NetworkInfo& item) {
        return item.IsConnected();
    });

    return 0;
}

关键修复点说明

  • 迭代器合规性:确保IteratorAsync实现了输入迭代器的所有必要操作(递增、解引用、相等比较)
  • 哨位兼容性:IteratorAsyncSentinel与IteratorAsync必须实现双向相等比较,满足std::sentinel_for概念
  • borrowed_range支持:通过特化std::ranges::enable_borrowed_range,让标准库允许直接使用容器调用范围版算法
  • 类型别名正确性:迭代器的value_type、reference等别名必须严格符合标准定义,否则概念检查会失败

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 21:05:05