std::ranges::views::filter
C++20 引入的视图适配器,用于根据谓词条件惰性过滤范围内的元素。
Defined in header | ||
template< ranges::input_range V, std::indirect_unary_predicate<ranges::iterator_t<V>> Pred > | (1) | (since C++20) |
namespace views { inline constexpr /* unspecified */ filter = /* unspecified */; } | (2) | (since C++20) |
Call signature | ||
template< ranges::viewable_range R, class Pred > requires /* see below */ constexpr ranges::view auto filter( R&& r, Pred&& pred ); | (since C++20) | |
template< class Pred > | (since C++20) |
以下是对其详细说明及示例:
基本用法
filter
接受一个谓词(返回 bool
的可调用对象),并生成仅包含满足条件元素的视图。
示例 1:过滤偶数
#include <iostream>
#include <vector>
#include <ranges>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5, 6};
auto even = vec | std::ranges::views::filter([](int i) { return i % 2 == 0; });
for (int n : even) {
std::cout << n << ' '; // 输出:2 4 6
}
}
。
动态条件过滤自定义类型
通过捕获变量,可动态调整过滤条件对象为自定义结构体或类。
示例 2:过滤成年人
#include <iostream>
#include <vector>
#include <ranges>
#include <string>
struct Person
{
int age;
std::string name;
};
void foo(int age)
{
std::vector<Person> people = {{20, "Alice"}, {15, "Bob"}, {25, "Charlie"}};
auto adults = people | std::ranges::views::filter([age](const Person& p) {
return p.age >= age;
});
for (const auto& p : adults)
{
std::cout << p.name << ' '; // 输出:Alice Charlie
}
}
int main()
{
foo(18);
}
组合视图适配器
通过管道符 |
链式组合多个视图适配器。
示例 3:过滤偶数后平方
auto processed = vec | std::ranges::views::filter([](int i) { return i % 2 == 0; })
| std::ranges::views::transform([](int i) { return i * i; });
for (int n : processed) {
std::cout << n << ' '; // 输出:4 16 36
}
示例 4:过滤非空字符串并转大写
std::vector<std::string> words = {"hello", "", "world", "", "cpp"};
auto non_empty_upper = words
| std::ranges::views::filter([](const std::string& s) { return !s.empty(); })
| std::ranges::views::transform([](std::string s) {
std::transform(s.begin(), s.end(), s.begin(), ::toupper);
return s;
});
for (const auto& s : non_empty_upper) {
std::cout << s << ' '; // 输出:HELLO WORLD CPP
}
反向迭代
若原始范围支持双向迭代,filter
视图可反向遍历(需注意效率)。
示例 6:反向输出偶数
for (auto it = even.rbegin(); it != even.rend(); ++it) {
std::cout << *it << ' '; // 输出:6 4 2
}
与 copy_if
的区别
-
filter
视图:惰性求值,不存储结果,适用于流式处理。 -
copy_if
算法:立即执行并将结果保存到容器中。
总结
-
惰性求值:仅在遍历时计算,节省内存。
-
链式组合:可与其他视图适配器(如
transform
、take
)灵活组合。 -
谓词灵活性:支持 Lambda、函数对象或成员函数。
-
迭代器依赖:迭代器类别继承自原始范围,可能影响性能。
transfrom和filter之间的问题
#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>
void test_transform_filter()
{
std::vector<int> coll{8,15,7,0,9};
auto vColl = coll | std::views::transform([](auto&& i)
{
std::cout << "transform " << i << '\n';
return -i;})
| std::ranges::views::filter([](int i){
std::cout << " filter " << i << '\n';
return i%3 == 0;
});
for (int val: vColl)
{
std::cout << "val: " << val << '\n';
}
}
void test_filter_transform()
{
std::vector<int> coll{8,15,7,0,9};
auto vColl = coll | std::ranges::views::filter([](int i){
std::cout << " filter " << i << '\n';
return i%3 == 0;
})
| std::views::transform([](auto&& i){
std::cout << "transform " << i << '\n';
return -i;});
for (int val: vColl)
{
std::cout << "val: " << val << '\n';
}
}
int main(void)
{
test_transform_filter();
std::cout << "-------------------------\n" << std::endl;
test_filter_transform();
return 0;
}
输出:
transform 8
filter -8
transform 15
filter -15
transform 15
val: -15
transform 7
filter -7
transform 0
filter 0
transform 0
val: 0
transform 9
filter -9
transform 9
val: -9
-------------------------
filter 8
filter 15
transform 15
val: -15
filter 7
filter 0
transform 0
val: 0
filter 9
transform 9
val: -9
从输出结果可以看出来,在transform | filter这种组合情况下,满足filter的item,会被transform两次。