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

C++20 ranges如何遍历已排序范围的equal_range等值区间?

解决方案

C20标准库没有内置直接满足需求的equal_range_split适配器,但可以自行实现符合C20 ranges规范的自定义视图适配器,完美支持管道式组合调用。

实现代码

#include <vector>
#include <ranges>
#include <iostream>
#include <algorithm>
#include <fmt/ranges.h>

template<std::ranges::forward_range R, typename Comp = std::ranges::equal_to>
requires std::ranges::view<R>
struct equal_range_split_view : std::ranges::view_interface<equal_range_split_view<R, Comp>> {
private:
    R base_;
    Comp comp_;
    std::ranges::iterator_t<R> current_ = std::ranges::begin(base_);

    struct iterator {
        using value_type = std::ranges::subrange<std::ranges::iterator_t<R>>;
        using difference_type = std::ranges::range_difference_t<R>;

        equal_range_split_view* parent_ = nullptr;

        value_type operator*() const {
            return std::ranges::equal_range(parent_->current_, std::ranges::end(parent_->base_), *parent_->current_, parent_->comp_);
        }

        iterator& operator++() {
            parent_->current_ = std::ranges::upper_bound(parent_->current_, std::ranges::end(parent_->base_), *parent_->current_, parent_->comp_);
            return *this;
        }

        iterator operator++(int) {
            auto tmp = *this;
            ++*this;
            return tmp;
        }

        bool operator==(const iterator& other) const {
            return parent_->current_ == other.parent_->current_;
        }
        bool operator==(std::ranges::default_sentinel_t) const {
            return parent_->current_ == std::ranges::end(parent_->base_);
        }
    };

public:
    equal_range_split_view() = default;
    equal_range_split_view(R base, Comp comp = Comp{}) : base_(std::move(base)), comp_(std::move(comp)), current_(std::ranges::begin(base_)) {}

    iterator begin() { return {this}; }
    std::ranges::default_sentinel_t end() const { return {}; }
};

// 适配器闭包实现,支持管道调用
namespace detail {
    struct equal_range_split_fn {
        template<std::ranges::forward_range R>
        auto operator()(R&& r) const {
            return equal_range_split_view(std::views::all(std::forward<R>(r)));
        }

        template<std::ranges::forward_range R, typename Comp>
        auto operator()(R&& r, Comp comp) const {
            return equal_range_split_view(std::views::all(std::forward<R>(r)), std::move(comp));
        }

        template<typename Comp = std::ranges::equal_to>
        auto operator()(Comp comp = {}) const {
            return std::ranges::range_adaptor_closure([comp = std::move(comp)]<std::ranges::forward_range R>(R&& r) {
                return equal_range_split_view(std::views::all(std::forward<R>(r)), comp);
            });
        }
    };
}

inline constexpr detail::equal_range_split_fn equal_range_split{};

// 测试代码
int main() {
    std::vector vals {1,2,2,3,3,3,47};
    // 完全符合期望的调用风格
    vals | equal_range_split | std::ranges::for_each([](const auto& eq_range) {
        std::cout << "size: " << eq_range.size() << "\n";
        std::cout << fmt::format("{}\n", eq_range);
    });
}

特性说明

  • 完全符合C++20 ranges规范,支持任意前向迭代器的已排序范围,惰性求值,无额外拷贝开销
  • 支持自定义比较谓词,针对自定义类型排序的场景,可传入自定义比较函数:vals | equal_range_split(std::greater{}) | ...
  • 具备完全的可组合性,可与其他标准库视图适配器链式调用,后续可接std::views::filter、std::views::transform等实现更复杂的逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 21:09:01