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

能否使range::remove作用于views::chunk?求解决方案

无法用ranges::remove操作ranges::views::chunk视图的问题及解决办法

经测试发现ranges::remove无法对ranges::views::chunk生成的视图进行操作,尝试移除首个元素为9的chunk时触发了concept约束错误。

测试代码如下:

#include "range/v3/algorithm/remove.hpp"
#include <iostream>
#include <range/v3/view/chunk.hpp>
#include <vector>

int main() {

    std::vector<int> v{
        1, 2, 3, 4,
        5, 6, 7, 8, 
        9, 10, 11, 12,
        13, 14, 15, 16
    };

    auto a = ranges::views::chunk(v, 4);
    for (const auto& e: a) std::cout << e[0] << "\n";

    auto it = ranges::remove(a, 9, [](const auto& e) { return e[0]; });

    // expected result  (xx means unspecified)

    // std::vector<int> v{
    //     1, 2, 3, 4,
    //     5, 6, 7, 8, 
    //     13, 14, 15, 16,
    //     xx, xx, xx, xx
    // };

}

报错信息显示该操作不满足permutable、forward_iterator等一系列concepts约束,具体错误片段如下:

constraints not satisfied [with I = ranges::chunk_view<ranges::ref_view<std::vector<int>>>, S = int, T = (lambda at
      /home/oliver/c/physicssim/app/parremove.cpp:19:36), P = ranges::identity]
        constexpr I RANGES_FUNC(remove)(I first, S last, T const & val, P proj = P{})
                    ^
/home/oliver/c/physicssim/ext/range-v3/include/range/v3/detail/config.hpp:633:27: note: expanded from macro
      'RANGES_FUNC'
#define RANGES_FUNC(NAME) operator() RANGES_FUNC_CONST_ /**/
                          ^
/home/oliver/c/physicssim/ext/range-v3/include/range/v3/algorithm/remove.hpp:42:22: note: because
      'ranges::chunk_view<ranges::ref_view<std::vector<int>>>' does not satisfy 'permutable'
            requires permutable<I> AND sentinel_for<S, I> AND
                     ^
/home/oliver/c/physicssim/ext/range-v3/include/range/v3/detail/prologue.hpp:35:26: note: expanded from macro
      'template'
    template<__VA_ARGS__ CPP_TEMPLATE_AUX_                                      \
                         ^
/home/oliver/c/physicssim/ext/range-v3/include/range/v3/iterator/concepts.hpp:841:9: note: because
      'ranges::chunk_view<ranges::ref_view<std::vector<int>>>' does not satisfy 'forward_iterator'
        forward_iterator<I> &&
        ^
/home/oliver/c/physicssim/ext/range-v3/include/range/v3/iterator/concepts.hpp:371:9: note: because
      'ranges::chunk_view<ranges::ref_view<std::vector<int>>>' does not satisfy 'input_iterator'
        input_iterator<I> &&
        ^
/home/oliver/c/physicssim/ext/range-v3/include/range/v3/iterator/concepts.hpp:363:9: note: because
      'ranges::chunk_view<ranges::ref_view<std::vector<int>>>' does not satisfy 'input_or_output_iterator'
        input_or_output_iterator<I> &&
        ^
....

问题原因

ranges::remove是原地修改算法,要求迭代器满足permutable(可置换)约束——意味着迭代器指向的元素可以被移动、交换,且迭代器本身支持双向遍历。但chunk_view的迭代器只是原容器的分段视图引用,它的"元素"是临时的子范围对象,并非可直接修改的独立元素,根本无法满足permutable的核心要求,所以会触发约束错误。

替代方案

方案1:直接操作原容器(高效,原地修改)

每个chunk对应原容器中连续的固定长度元素,要移除目标chunk,等价于移除原容器中对应的连续区间。比如要移除首个元素为9的chunk,直接定位到该元素在原容器中的位置,再按chunk大小计算要删除的区间:

#include "range/v3/algorithm/find.hpp"
#include <iostream>
#include <vector>

int main() {
    std::vector<int> v{
        1, 2, 3, 4,
        5, 6, 7, 8, 
        9, 10, 11, 12,
        13, 14, 15, 16
    };

    // 找到首个值为9的元素的迭代器
    auto target = ranges::find(v, 9);
    if (target != v.end()) {
        // 计算该元素所在chunk的起始位置(对齐到chunk大小的倍数)
        auto chunk_idx = (target - v.begin()) / 4;
        auto chunk_start = v.begin() + chunk_idx * 4;
        // 删除整个chunk
        v.erase(chunk_start, chunk_start + 4);
    }

    // 输出验证
    for (int num : v) {
        std::cout << num << " ";
    }
    // 输出:1 2 3 4 5 6 7 8 13 14 15 16
}

方案2:转换为容器后操作(灵活,但会复制数据)

如果不想直接操作原容器,可以先把chunk视图转换成实际的容器(比如vector<vector<int>>),移除目标chunk后再合并回原容器:

#include "range/v3/algorithm/remove_if.hpp"
#include <iostream>
#include <range/v3/view/chunk.hpp>
#include <vector>

int main() {
    std::vector<int> v{
        1, 2, 3, 4,
        5, 6, 7, 8, 
        9, 10, 11, 12,
        13, 14, 15, 16
    };

    auto a = ranges::views::chunk(v, 4);
    // 将视图转为实际容器
    std::vector<std::vector<int>> chunks(a.begin(), a.end());
    
    // 移除首个元素为9的chunk
    chunks.erase(ranges::remove_if(chunks.begin(), chunks.end(),
        [](const auto& chunk) { return chunk[0] == 9; }), chunks.end());
    
    // 合并回原容器
    v.clear();
    for (const auto& chunk : chunks) {
        v.insert(v.end(), chunk.begin(), chunk.end());
    }

    // 输出验证
    for (int num : v) {
        std::cout << num << " ";
    }
}

方案3:使用filter视图过滤(不修改原容器,仅用于遍历)

如果不需要修改原容器,只是想在遍历时跳过目标chunk,直接用views::filter即可:

#include <iostream>
#include <range/v3/view/chunk.hpp>
#include <range/v3/view/filter.hpp>
#include <vector>

int main() {
    std::vector<int> v{
        1, 2, 3, 4,
        5, 6, 7, 8, 
        9, 10, 11, 12,
        13, 14, 15, 16
    };

    auto filtered_chunks = ranges::views::chunk(v, 4) 
                         | ranges::views::filter([](const auto& chunk) { return chunk[0] != 9; });

    // 遍历过滤后的视图
    for (const auto& chunk : filtered_chunks) {
        std::cout << chunk[0] << "\n";
    }
    // 输出:1 5 13
}

内容的提问来源于stack exchange,提问作者Oliver Schönrock

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 12:05:12