# 函数对象
函数对象分类:
- 发生器
- 一元函数
- 二元函数
- 一元判定函数
- 二元判定函数
函数对象的基本写法:重载 operator()
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
class CSum {
private:
int sum;
public:
CSum() { sum = 0; }
// 注意写法:
void operator()(int n) { sum += n; }
int getSum() { return sum; }
};
int main() {
vector<int> v;
for (int i = 1; i <= 100; i++) {
v.push_back(i);
}
CSum sObj = for_each(v.begin(), v.end(), CSum());
cout << sObj.getSum() << endl;
return 0;
}
# 函数适配器
# 绑定
用来在函数对象上左一个扩充,依然使用之前的函数对象,但是使用了延伸的功能
bind1st()
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main() {
int numbers[] = {10, 20, 30, 40, 50, 60};
int cx;
cx = count_if(numbers, numbers + 6, bind2nd(less<int>(), 40));
cout << "There are " << cx << " elements that are less than 40.\n";
cx = count_if(numbers, numbers + 6, bind1st(less<int>(), 40));
cout << "There are " << cx << " elements that are not less than 40.\n";
return 0;
}
分析
less()
是一个二元函数对象, less(a, b)
表示判断 a < b
是否成立。
所以 bind2nd(less<int>(), 40)
相当于 x < 40
是否成立,用于判定那些小于 40 的元素。
bind1st(less<int>(), 40)
相当于 40 < x
是否成立,用于判定那些大于 40 的元素。
# bind()
bind1st () 和 bind2nd (),在 C++11 里已经 deprecated 了。bind () 可以替代他们,且用法更灵活更方便。
上面的例子可以写成下面的形式:
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
int main() {
int numbers[] = {10, 20, 30, 40, 50, 10};
int cx;
cx = count_if(numbers, numbers + 6, bind(less<int>(), std::placeholders::_1, 40));
cout << "There are " << cx << " elements that are less than 40.\n";
cx = count_if(numbers, numbers + 6, bind(less<int>(), 40, std::placeholders::_1));
cout << "There are " << cx << " elements that are not less than 40.\n";
return 0;
}
std::placeholders::_1
是占位符,标定这个是要传入的参数。
所以 bind()
不仅可以用于二元函数,还可以用于多元函数,可以绑定多元函数中的多个参数,不想绑定的参数使用占位符表示。
此用法更灵活,更直观,更便捷。
# 取反
std::not1 和 std::not2 是用来把,符合某种特殊条件的『函数对象』转换为反义「函数对象」的函数。
not1 是构造一个与谓词结果相反的一元函数对象。
not2 是构造一个与谓词结果相反的二元函数对象。
// not1 example
#include <algorithm> // std::count_if
#include <functional> // std::not1
#include <iostream> // std::cout
struct IsOdd { //是否为奇数
bool operator()(const int& x) const { return x % 2 == 1; }
};
int main() {
int values[] = {1, 2, 3, 4, 5};
int cx = std::count_if(values, values + 5, std::not1(IsOdd()));
//计算不为奇数的个数
std::cout << "There are " << cx << " elements with even values.\n";
return 0;
}
not2 示例:
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main() {
std::vector<int> nums = {5, 3, 4, 9, 1, 7, 6, 2, 8};
// 升序
std::function<bool(int, int)> ascendingOrder = [](int a, int b) {
return a < b;
};
// 排序,不是按升序,而是按降序
std::sort(nums.begin(), nums.end(), std::not2(ascendingOrder));
for (int i : nums) {
std::cout << i << " ";
}
return 0;
}
# 成员函数适配器
mem_fun_ref 的作用和用法跟 mem_fun 一样,将成员函数变成函数对象
唯一的不同就是:当容器中存放的是对象实体的时候用 mem_fun_ref,当容器中存放的是对象的指针的时候用 mem_fun。
#include <algorithm> // for_each()
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
class Test {
public:
int doSomething() {
cout << "output from method doSomething" << endl;
return 1;
}
};
int doSome(Test *test) { return test->doSomething(); }
// 声明一个使用成员函数的全局函数
int main() {
vector<Test *> v;
for (int i = 0; i < 5; ++i) {
Test *t = new Test();
v.push_back(t);
}
// 若不想调用 doSome() 函数,而是想调用成员函数
// 就可以使用 mem_fun 将对象的方法转换为函数对象的用法
for_each(v.begin(), v.end(), mem_fun(&Test::doSomething));
return 0;
}
# 普通函数适配器
为了配合 bind 使用,普通的函数不可以使用绑定函数适配器,所以使用 ptr_fun 作为 bind 的参数,实现普通函数用法向函数对象用法的转换
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
bool g(int x, int y) { return x > y; }
int main() {
int a[] = {2, 5, 3, 7, 1, 9, 8, 0, 6};
int nSize = sizeof(a) / sizeof(int);
int nCount = count_if(a, a + nSize, bind2nd(ptr_fun(g), 3));
// 这里不能写 bind2nd(g, 3)
cout << nCount;
return 0;
}