迭代对容器应用range-v3 views::filter时出现类型不匹配赋值错误如何解决
问题原因
你遇到的赋值错误本质是每一层ranges::views::filter返回的view类型都和上一层不同:
- 第一次初始化
results时,auto推导的类型是filter_view<ref_view<vector<int>>, 第一个lambda类型> - 每次循环追加filter后,返回的类型会多套一层
filter_view,同时绑定的是全新的lambda类型,和初始results的类型完全不兼容,自然没有匹配的赋值运算符。
解决方案1:使用类型擦除的
any_view适配不同类型的view ranges库提供了ranges::any_view用来做类型擦除,只要元素类型匹配,任意符合要求的view都可以赋值给它,完全符合你逐层叠加filter、保留惰性求值的需求:
#include <iostream> #include <vector> #include <numeric> #include <cmath> #include <range/v3/all.hpp> int main() { int limit = 100; std::vector<int> numbers(100); std::iota(numbers.begin(), numbers.end(), 1); // 声明为元素类型是int的任意view,做类型擦除 ranges::any_view<int> results = numbers | ranges::views::filter([](int n) {return n != 1; }); int sqrt_limit = std::sqrt(limit); for (int i = 2; i <= sqrt_limit; i++) { results = results | ranges::views::filter([i](int n) {return n == i || n % i != 0; }); } // 测试输出100以内素数 for (auto num : results) { std::cout << num << " "; } }
解决方案2:合并过滤谓词,只使用一层filter
你也可以把所有过滤逻辑合并到同一个filter的谓词里,不需要修改view类型,逻辑更直观、运行效率更高:
#include <iostream> #include <vector> #include <numeric> #include <cmath> #include <range/v3/all.hpp> int main() { int limit = 100; std::vector<int> numbers(100); std::iota(numbers.begin(), numbers.end(), 1); int sqrt_limit = std::sqrt(limit); auto results = numbers | ranges::views::filter([&](int n) { if (n == 1) return false; for (int i = 2; i <= sqrt_limit; i++) { if (n != i && n % i == 0) return false; } return true; }); // 测试输出100以内素数 for (auto num : results) { std::cout << num << " "; } }
如果不需要保留view的惰性求值特性,你也可以每次叠加filter后用ranges::to<std::vector<int>>直接求值为容器再赋值,不过会产生多次内存拷贝,仅适合小数据量场景使用。
内容的提问来源于stack exchange,提问作者kingpin
相关产品推荐
相关产品推荐

