std::all_of / std::any_of / std::none_of
这三个算法用同一个一元谓词 p 检查范围内的元素,分别回答三个问题:
all_of:是否所有元素都满足p?any_of:是否存在元素满足p?none_of:是否没有元素满足p?
它们都是短路求值的,一旦结论确定就立即返回,不会继续扫描剩余元素。
1. 引入
#include <algorithm>
2. 原理
template<class InputIt, class UnaryPred>
constexpr bool all_of(InputIt first, InputIt last, UnaryPred p);
template<class InputIt, class UnaryPred>
constexpr bool any_of(InputIt first, InputIt last, UnaryPred p);
template<class InputIt, class UnaryPred>
constexpr bool none_of(InputIt first, InputIt last, UnaryPred p);
- 迭代器要求:
InputIterator。 - 复杂度:至多 \( O(n) \) 次谓词调用,实际调用次数取决于何时能得出结论。
- 空范围:
all_of和none_of对空范围返回true(空真命题),any_of返回false。
三者的逻辑关系如下:
| 算法 | 等价写法 | 空范围结果 |
|---|---|---|
all_of | !any_of(..., !p) | true |
any_of | !none_of(...) | false |
none_of | !any_of(...) | true |
ranges:: 版本额外支持投影,可以只对元素的某个成员进行判断。
3. 用法
(1) 基本用法
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{2, 4, 6, 8};
bool allEven = std::all_of(v.begin(), v.end(), [](int x) { return x % 2 == 0; });
bool anyOdd = std::any_of(v.begin(), v.end(), [](int x) { return x % 2 != 0; });
bool noneNeg = std::none_of(v.begin(), v.end(), [](int x) { return x < 0; });
std::cout << std::boolalpha
<< allEven << '\n' // true
<< anyOdd << '\n' // false
<< noneNeg << '\n'; // true
}
(2) 谓词与投影
ranges:: 版本支持投影,可以直接对成员做判断:
struct Person { std::string name; int age; };
std::vector<Person> people{{"Alice", 30}, {"Bob", 25}};
// 是否所有成年人都年满 18 岁
bool allAdult = std::ranges::all_of(people, [](int age) { return age >= 18; },
&Person::age); // true
(3) 执行策略
这三个算法不支持执行策略。原因是它们需要短路求值,而并行执行无法保证「一旦得出结论就停止」,因此标准没有提供并行版本。
4. 注意事项
- 空范围的真假:
all_of与none_of对空范围返回true,这符合数学上的空真(vacuous truth),但容易与直觉不符,使用前最好先确认范围非空。 - 谓词不应有副作用:标准不保证谓词被调用的次数,也不保证调用顺序。
none_of不等于!all_of:none_of(p)等价于!any_of(p),而不是!all_of(p)。- 短路特性:如果谓词开销大,把最可能失败的判断放在前面可以提前结束。
5. 相关算法
- find / find_if:找出第一个满足条件的元素
- count / count_if:统计满足条件的元素数量
- equal:比较两个范围是否相同
- search:查找子序列