C++ ranges:切换至filter_view时调用size()报错,transform_view正常
为什么filter_view不能调用size(),而transform_view可以?
错误原因
C++20引入的Ranges库中,视图是否支持size()取决于它是否满足Sized Range概念:
transform_view只是对原range的每个元素做转换,不会改变元素数量,因此继承了原range(这里是iota_view)的Sized属性,能直接返回原range的大小,所以可以调用size()。filter_view是根据过滤条件筛选元素,过滤后的元素数量无法在O(1)时间内确定(必须遍历所有元素才能统计符合条件的数量),因此它不属于Sized Range,既没有size()成员函数,也不支持operator[](无法通过索引直接定位元素)。
你代码里的output.size()和output[i]在使用filter时报错,本质都是因为filter_view不支持Sized和Random Access特性。
解决方法
方法1:使用范围for循环(推荐,符合Ranges设计理念)
直接遍历视图元素,不需要依赖size和索引:
#include <iostream> #include <ranges> #include <sstream> int main() { using namespace std; auto input = views::iota(1, 5 + 1); auto output = input | views::filter([](auto n) { return n % 2 == 0; }); stringstream ss; ss << "["; bool first = true; for (auto num : output) { if (!first) ss << ','; ss << num; first = false; } ss << "]"; cout << ss.str(); return 0; }
方法2:将视图转换为容器(如果需要频繁使用size或索引)
把filter后的视图转成vector这类支持size和随机访问的容器:
#include <iostream> #include <ranges> #include <sstream> #include <vector> int main() { using namespace std; auto input = views::iota(1, 5 + 1); auto output = input | views::filter([](auto n) { return n % 2 == 0; }); vector<int> filtered(output.begin(), output.end()); // 转换为vector stringstream ss; ss << "["; for (auto i = 0; i < filtered.size() - 1; ++i) { ss << filtered[i] << ','; } ss << filtered[filtered.size() - 1]; ss << "]"; cout << ss.str(); return 0; }
方法3:手动计算size(不推荐,效率低)
如果一定要保留原有循环结构,可以先遍历一遍视图统计元素数量,但会导致两次遍历,效率不高:
#include <iostream> #include <ranges> #include <sstream> #include <iterator> int main() { using namespace std; auto input = views::iota(1, 5 + 1); auto output = input | views::filter([](auto n) { return n % 2 == 0; }); // 手动计算size auto size = distance(output.begin(), output.end()); stringstream ss; ss << "["; auto it = output.begin(); for (auto i = 0; i < size - 1; ++i) { ss << *it << ','; ++it; } if (size > 0) ss << *it; ss << "]"; cout << ss.str(); return 0; }
内容的提问来源于stack exchange,提问作者D G
相关产品推荐
相关产品推荐

