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

std::ranges中是否有range-v3 views::cache1的替代方案?

std::ranges中views::cache1的替代实现

标准C++20/23的std::ranges库并没有内置对应range-v3中views::cache1的视图,但你可以轻松实现一个轻量版本——它的核心逻辑就是缓存最近迭代到的元素,避免对计算开销大的range重复求值,非常适合复杂计算、IO绑定的场景。

以下是符合标准ranges规范的cache1视图实现:

#include <ranges>
#include <optional>

template<std::ranges::input_range R>
requires std::copyable<std::ranges::range_value_t<R>>
class cache1_view : public std::ranges::view_interface<cache1_view<R>> {
private:
    R base_;
    mutable std::optional<std::ranges::range_value_t<R>> cached_val_;
    mutable std::ranges::iterator_t<R> current_iter_ = std::ranges::begin(base_);
    mutable bool is_cached_ = false;

public:
    cache1_view() = default;
    explicit cache1_view(R base) : base_(std::move(base)), current_iter_(std::ranges::begin(base_)) {}

    struct iterator {
        using value_type = std::ranges::range_value_t<R>;
        using difference_type = std::ranges::range_difference_t<R>;
        using iterator_category = std::input_iterator_tag;

        cache1_view* parent_ = nullptr;
        bool is_end_ = false;

        iterator() = default;
        explicit iterator(cache1_view* parent, bool is_end) : parent_(parent), is_end_(is_end) {}

        value_type operator*() const {
            if (!parent_->is_cached_) {
                parent_->cached_val_ = *parent_->current_iter_;
                parent_->is_cached_ = true;
            }
            return *parent_->cached_val_;
        }

        iterator& operator++() {
            if (!is_end_) {
                ++parent_->current_iter_;
                parent_->is_cached_ = false;
                is_end_ = (parent_->current_iter_ == std::ranges::end(parent_->base_));
            }
            return *this;
        }

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

        bool operator==(const iterator& other) const {
            if (is_end_ && other.is_end_) return true;
            if (is_end_ != other.is_end_) return false;
            return parent_->current_iter_ == other.parent_->current_iter_;
        }
    };

    iterator begin() { return iterator(this, false); }
    iterator end() { return iterator(this, true); }
};

namespace views {
    inline constexpr auto cache1 = []<std::ranges::input_range R>(R&& r) {
        return cache1_view<std::views::all_t<R>>(std::views::all(std::forward<R>(r)));
    };
}

实现说明

  • 该视图仅缓存当前迭代器指向的元素,每次迭代前进时会清除缓存标记,确保下一次取值时重新计算并缓存。
  • 满足输入范围的要求,支持所有元素可拷贝的输入类型range。
  • 完全兼容标准ranges的链式调用语法。

使用示例

假设你有一个计算开销极大的transform视图,用cache1包裹后,多次遍历同一个range时每个元素只会被计算一次:

#include <iostream>
#include <chrono>
#include <thread>

// 模拟高开销计算
auto heavy_calculation = [](int x) {
    std::cout << "[Computing] " << x << "\n";
    // 模拟耗时操作
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    return x * 3;
};

int main() {
    auto cached_range = std::views::iota(1, 4) 
                      | std::views::transform(heavy_calculation) 
                      | views::cache1;

    // 第一次遍历:触发计算
    std::cout << "First pass:\n";
    for (int val : cached_range) {
        std::cout << val << " ";
    }
    std::cout << "\n";

    // 第二次遍历:直接使用缓存,无计算输出
    std::cout << "Second pass:\n";
    for (int val : cached_range) {
        std::cout << val << " ";
    }
    std::cout << "\n";

    return 0;
}

运行后会看到,三次计算只会在第一次遍历时触发,第二次遍历直接读取缓存值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 09:35:24