目录
1. 什么是谓词(断言函数)(predicate)?
一直以来,很多书都翻译成“谓词”,是因为英语中对应的单词是“predicate”。但将这个称为“谓词”却很容易搞混淆,更准确地应称为“断言函数”。
断言要求描述一个返回 BooleanTestable 值的可调用函数。BooleanTestable指定这种类型和值类别的表达式可转换为 bool 类型,并且该类型或两个不同 BooleanTestable 类型的逻辑运算符具有通常的行为。其本质是将这种简单重复判断的工作交给模板通用模块去处理,传递函数地址以方便通用模块内部调用逻辑判断函数,即将遍历对比任务交给通用板块。
断言通常用于接受输入数据(单个对象/容器)和断言的算法,然后对输入数据调用断言来决定进一步的操作。C++ 标准库中的一些断言用法的例子有:
• std::all_of,std::any_of,std::none_of 将元素数组和断言作为输入。对各个输入元素调用断言函数,如果对于所有/任何/无元素,断言算法返回 true,则断言函数返回 true。
• std::find_if 取元素序列和断言。返回序列中断言返回值等于 true 的第一个元素。
2. 几个断言函数的定义
几个断言函数其实是作为模板函数定义的:
定义于头文件 <algorithm> | ||
template< class InputIt, class UnaryPred > | (1) | (since C++11) |
template< class ExecutionPolicy, class ForwardIt, class UnaryPred > bool all_of( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryPred p ); | (2) | (since C++17) |
template< class InputIt, class UnaryPred > | (3) | (since C++11) |
template< class ExecutionPolicy, class ForwardIt, class UnaryPred > bool any_of( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryPred p ); | (4) | (since C++17) |
template< class InputIt, class UnaryPred > | (5) | (since C++11) |
template< class ExecutionPolicy, class ForwardIt, class UnaryPred > bool none_of( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryPred p ); | (6) | (since C++17) |
(1) 检查一元谓词 p 是否对范围 [first, last) 中的至少一个元素返回 false。
(3) 检查一元谓词 p 是否对范围 [first, last) 中的至少一个元素返回 true。
(5) 检查一元谓词 p 是否对范围 [first, last) 中的任何元素均不返回 true。
(2,4,6) 与 (1,3,5) 相同,但根据策略执行。
仅当满足以下所有条件时,这些重载才会参与重载决议:
std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> 是 true. | (until C++20) |
std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> 是 true. | (since C++20) |
参数说明:
first ,last —— 定义要检查的元素之范围的成对迭代器。
Policy —— 执行检查的执行策略。
P —— 一元谓词(实际上是带一个参数的函数,返回值是bool ,实际调用时传函数地址)。
对于每一个类型为VT(可能是const)的参数v (其中 VT 是 InputIt 的值类型(ValueType),与值类别无关,并且不能修改 v),表达式 p(v) 必须能够转换为 bool。因此,不允许使用 VT& 的参数类型,也不允许使用 VT,除非对于 VT 来说,移动等同于复制(自 C++11 起)。
类型要求:
InputIt 必须满足 LegacyInputIterator 的要求。
ForwardIt 必须满足 LegacyForwardIterator 的要求。
UnaryPred 必须满足 Predicate 的要求。
3. 用法示例
例1:
#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
int main()
{
std::vector<int> v(10, 2);
std::partial_sum(v.cbegin(), v.cend(), v.begin());
std::cout << "Among the numbers: ";
std::copy(v.cbegin(), v.cend(), std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
if (std::all_of(v.cbegin(), v.cend(), [](int i) { return i % 2 == 0; }))
std::cout << "All numbers are even\n";
if (std::none_of(v.cbegin(), v.cend(), std::bind(std::modulus<>(),
std::placeholders::_1, 2)))
std::cout << "None of them are odd\n";
struct DivisibleBy
{
const int d;
DivisibleBy(int n) : d(n) {}
bool operator()(int n) const { return n % d == 0; }
};
if (std::any_of(v.cbegin(), v.cend(), DivisibleBy(7)))
std::cout << "At least one number is divisible by 7\n";
}
输出:
Among the numbers: 2 4 6 8 10 12 14 16 18 20
All numbers are even
None of them are odd
At least one number is divisible by 7
例2:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool is_even(int n) {
return (n % 2 == 0);
}
int main(void) {
vector<int> v = {2, 4, 6, 8, 10};
bool result;
result = all_of(v.begin(), v.end(), is_even);
if (result == true)
cout << "Vector contains all even numbers." << endl;
v[0] = 1;
result = all_of(v.begin(), v.end(), is_even);
if (result == false)
cout << "Vector doesn't contain all even numbers." << endl;
return 0;
}