C++之STL整理(7)之各种仿函数用法(算术类、比较类、逻辑类)整理
注:整理一些突然学到的C++知识,随时mark一下
例如:忘记的关键字用法,新关键字,新数据结构
C++ 的仿函数用法整理
提示:本文为 C++ 中仿函数的写法和举例
一、仿函数
1、functional库的内建仿函数
仿函数除了可以当作函数调用使用还可以作为函数对象当成参数传递。STL中为了与算法配合,已经封装好了一些常用功能的仿函数。这些内建的仿函数(functors)或称函数对象(function objects)本质是预定义的类模板,它们重载了操作符以模拟函数的行为。这些仿函数通常用于算法中,比如执行特定的算术操作、关系比较或逻辑运算。需要引入头文件 #include< functional>
来使用这些仿函数。
以下是STL中一些常用的内建仿函数及其简单描述:
算术仿函数
std::plus<T>
:执行加法运算。
std::minus<T>
:执行减法运算。
std::multiplies<T>
:执行乘法运算。
std::divides<T>
:执行除法运算。
std::modulus<T>
:执行取模运算(求余数)。
std::negate<T>
:执行一元取相反数运算。
关系仿函数
std::equal_to<T>
:判断两个元素是否相等。
std::not_equal_to<T>
:判断两个元素是否不相等。
std::greater<T>
:判断第一个元素是否大于第二个元素。
std::less<T>
:判断第一个元素是否小于第二个元素。
std::greater_equal<T>
:判断第一个元素是否大于或等于第二个元素。
std::less_equal<T>
:判断第一个元素是否小于或等于第二个元素。
逻辑仿函数
std::logical_and<T>
:执行逻辑与运算。
std::logical_or<T>
:执行逻辑或运算。
std::logical_not<T>
:执行逻辑非运算。
这些仿函数使得STL算法更加灵活和可重用。通过传递不同的仿函数给算法,我们可以改变算法的行为,而无需修改算法本身的代码。
2、算术仿函数()
下面将给出每个内建仿函数与中算法结合使用的示例代码:
plus<T>
#include <iostream>
#include <vector>
#include <numeric> // for std::accumulate
#include <functional> // for std::plus
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
int sum = std::accumulate(nums.begin(), nums.end(), 0, std::plus<int>());
std::cout << "Sum: " << sum << std::endl; // 输出: Sum: 15
return 0;
}
在这个例子中,std::accumulate算法使用std::plus仿函数来计算numbers向量中所有元素的和。注意,从C++11开始,你可以直接使用lambda表达式来替代仿函数
,使得代码更加简洁:
int sum = std::accumulate(numbers.begin(), numbers.end(), 0, [](int a, int b) { return a + b; });
minus<T>
#include <iostream>
#include <vector>
#include <numeric> // for std::partial_sum
#include <functional> // for std::minus
#include <iterator> // for std::ostream_iterator
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
std::vector<int> differences;
std::partial_sum(nums.begin(), nums.end(), std::back_inserter(differences), std::minus<int>());
// differences 现在是 {0, -1, -3, -6, -10}
std::copy(differences.begin(), differences.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl; // 输出: 0 -1 -3 -6 -10
return 0;
}
multiplies<T>
#include <iostream>
#include <vector>
#include <numeric> // for std::transform
#include <functional> // for std::multiplies
#include <iterator> // for std::ostream_iterator
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
std::vector<int> products(nums.size());
int factor = 2;
std::transform(nums.begin(), nums.end(), products.begin(), std::bind(std::multiplies<int>(), std::placeholders::_1, factor));
// products 现在是 {2, 4, 6, 8, 10}
std::copy(products.begin(), products.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl; // 输出: 2 4 6 8 10
return 0;
}
divides<T>
#include <iostream>
#include <vector>
#include <numeric> // for std::transform
#include <functional> // for std::divides
#include <iterator> // for std::ostream_iterator
int main() {
std::vector<int> nums = {10, 20, 30, 40, 50};
std::vector<double> quotients(nums.size());
int divisor = 5;
std::transform(nums.begin(), nums.end(), quotients.begin(), std::bind(std::divides<double>(), std::placeholders::_1, divisor));
// quotients 现在是 {2, 4, 6, 8, 10}
std::copy(quotients.begin(), quotients.end(), std::ostream_iterator<double>(std::cout, " "));
std::cout << std::endl; // 输出: 2 4 6 8 10
return 0;
}
modulus<T>
#include <iostream>
#include <vector>
#include <numeric> // for std::transform
#include <functional> // for std::modulus
#include <iterator> // for std::ostream_iterator
int main() {
std::vector<int
nums = {10, 20, 30, 40, 50};
std::vector<int> remainders(nums.size());
int divisor = 3;
std::transform(nums.begin(), nums.end(), remainders.begin(), std::bind(std::modulus<int>(), std::placeholders::_1, divisor));
// remainders 现在是 {1, 2, 0, 1, 2}
std::copy(remainders.begin(), remainders.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl; // 输出: 1 2 0 1 2
return 0;
}
negate<T>
#include <iostream>
#include <vector>
#include <algorithm> // for std::transform
#include <functional> // for std::negate
#include <iterator> // for std::ostream_iterator
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
std::vector<int> negatives(nums.size());
std::transform(nums.begin(), nums.end(), negatives.begin(), std::negate<int>());
// negatives 现在是 {-1, -2, -3, -4, -5}
std::copy(negatives.begin(), negatives.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl; // 输出: -1 -2 -3 -4 -5
return 0;
}
3、关系运算类函数对象
equal_to<T>
#include <iostream>
#include <vector>
#include <algorithm> // for std::find_if
#include <functional> // for std::equal_to
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
auto it = std::find_if(nums.begin(), nums.end(), std::bind(std::equal_to<int>(), std::placeholders::_1, 3));
if (it != nums.end()) {
std::cout << "Found number: " << *it << std::endl; // 输出: Found number: 3
} else {
std::cout << "Number not found." << std::endl;
}
return 0;
}
not_equal_to<T>
#include <iostream>
#include <vector>
#include <algorithm> // for std::find_if
#include <functional> // for std::not_equal_to
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
auto it = std::find_if(nums.begin(), nums.end(), std::bind(std::not_equal_to<int>(), std::placeholders::_1, 3));
if (it != nums.end()) {
std::cout << "Found a number not equal to 3: " << *it << std::endl; // 输出: Found a number not equal to 3: 1
} else {
std::cout << "No number found." << std::endl;
}
return 0;
}
greater<T>, greater_equal<T>, less<T>, less_equal<T>
这些仿函数与std::find_if、std::sort
等算法结合使用,可以很容易地实现排序和查找特定条件的元素。下面是一个使用std::greater和std::find_if联合使用的例子:有一个整数向量,我们想要找到第一个大于某个特定值的元素。
#include <iostream>
#include <vector>
#include <algorithm> // for std::find_if
#include <functional> // for std::greater
int main() {
std::vector<int> nums = {1, 3, 5, 7, 9};
int target = 4; // 我们要找的是第一个大于4的元素
// 使用 std::greater<int> 和 std::find_if 联合查找
auto it = std::find_if(nums.begin(), nums.end(), std::bind(std::greater<int>(), std::placeholders::_1, target));
if (it != nums.end()) {
std::cout << "Found a number greater than " << target << ": " << *it << std::endl;
} else {
std::cout << "No number greater than " << target << " found." << std::endl;
}
return 0;
}
在这个例子中,std::greater是一个函数对象,它接受两个整数参数并返回一个布尔值,表示第一个参数是否大于第二个参数。std::find_if是一个算法,它接受一个范围(由开始和结束迭代器定义)和一个谓词(在这里是std::greater),并返回第一个使谓词为真的元素的迭代器。如果没有找到这样的元素,它返回结束迭代器。
std::bind
用于将std::greater的第二个参数绑定到target变量上,这样每次调用比较操作时都会使用这个固定的target值。(后面会讲)
当运行这个程序时,它会输出:
Found a number greater than 4: 5
因为5是向量中第一个大于4的元素。如果没有任何元素大于4,则输出会是:
No number greater than 4 found.
4、逻辑运算类函数对象
logical_and<T>
以下是用lambda表达式实现的,来查找第一个满足n > 2 && n < 5条件的元素
#include <iostream>
#include <vector>
#include <algorithm> // for std::find_if
#include <functional> // for std::logical_and
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
auto it = std::find_if(nums.begin(), nums.end(), [](int n){ return n > 2 && n < 5; });
if (it != nums.end()) {
std::cout << "Found number: " << *it << std::endl; // 输出: Found number: 3
} else {
std::cout << "Number not found." << std::endl;
}
return 0;
}
也可以使用 std::logical_and
,要使用std::logical_and替换lambda表达式,我们需要组合使用std::bind和std::greater<int>以及std::less<int>函数对象
,然后将它们通过std::logical_and结合起来。以下是修改后的代码:
#include <iostream>
#include <vector>
#include <algorithm> // for std::find_if
#include <functional> // for std::logical_and, std::bind, std::greater, std::less
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
// 创建一个谓词,用于检查元素是否大于2且小于5
auto predicate = std::bind(std::logical_and<bool>(),
std::bind(std::greater<int>(), std::placeholders::_1, 2),
std::bind(std::less<int>(), std::placeholders::_1, 5));
// 使用find_if查找满足条件的元素
auto it = std::find_if(nums.begin(), nums.end(), predicate);
if (it != nums.end()) {
std::cout << "Found number: " << *it << std::endl; // 输出: Found number: 3
} else {
std::cout << "Number not found." << std::endl;
}
return 0;
}
在这个例子中,我们创建了一个名为predicate的谓词,它使用std::bind
将std::greater<int>
和std::less<int>
的函数对象与std::logical_and结合起来。std::placeholders::_1是一个占位符**,表示谓词中的第一个参数(在这里是nums中的元素**)。然后,我们使用这个predicate作为std::find_if的第三个参数,来查找第一个满足n > 2 && n < 5条件的元素。请注意,虽然这种方法展示了如何使用std::logical_and,但在实际编程中,使用lambda表达式通常会使代码更加简洁和易于理解。上面使用std::bind的代码相对复杂,而且可读性较差。因此,在C++11及更高版本中,推荐使用lambda表达式来实现类似的功能。