介绍
函数对象又称高阶函数,是一组重载的函数模板,用来向一个函数(或函数对象)绑定某些参数.
实际使用中可以作为参数传递给另一个函数,或者作为某函数的返回值的一类函数。
Boost.Bind
源码
boost/bind.hpp
简单使用
一元函数
#include <boost/bind.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void print(const int num)
{
cout << num <<endl;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
std::for_each(v.begin(), v.end(), print);
std::for_each(v.begin(), v.end(), boost::bind(print, _1)); // 和上一行输出一样,相当于对vector的每个元素x调用 boost::bind(print, _1)(x)
for (size_t index = 0; index < v.size(); index++)
{
boost::bind(print, _1)(v[index]);
}
}
二元函数(只提供一个参数)
#include <boost/bind.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void print(const int a, const int b)
{
cout << a << " " << b << endl;
}
void print3(const int a, const int b, const int c)
{
cout << a << " " << b << " " << c << endl;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
std::for_each(v.begin(), v.end(), boost::bind(print, 10, _1)); // 相当于对vector的每个元素x调用 print(10, x),用x取代占位符_1
std::for_each(v.begin(), v.end(), boost::bind(print, _1, 10)); // 相当于对vector的每个元素x调用 print(x, 10),用x取代占位符_1
for (size_t index = 0; index < v.size(); index++)
{
boost::bind(print, 10, _1)(v[index]);
}
std::for_each(v.begin(), v.end(), boost::bind(print3, 11, _1, 33)); // 相当于对vector的每个元素x调用 print3(11, x, 33),用x取代占位符_1
std::for_each(v.begin(), v.end(), boost::bind(print3, _1, 22, 33)); // 相当于对vector的每个元素x调用 print3(x, 22, 33),用x取代占位符_1
for (size_t index = 0; index < v.size(); index++)
{
boost::bind(print3, 44, _1, _2)(v[index], 55);
}
}
二元函数(提供两个参数)
#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
bool compare(int i, int j)
{
return i > j;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
// sort 根据第三个参数func 返回值判断顺序, true 表示x1 在x2前面
std::sort(v.begin(), v.end(), boost::bind(compare, _1, _2)); // func(x1, x2) => boost::bind(compare, _1, _2))(x1, x2) => compare(x1, x2),当x1 > x2 时返回true,所以从大到小排序
//std::sort(v.begin(), v.end(), compare);
for (size_t i = 0; i < v.size(); i++)
{
cout << v[i] <<endl;
}
//std::sort(v.begin(), v.end(), boost::bind(compare, _2, _2)); // 相当于compare(x2, x2) 元素自己比较,不会改变顺序
std::sort(v.begin(), v.end(), boost::bind(compare, _2, _1)); // func(x1, x2) => boost::bind(compare, _2, _1))(x1, x2) => compare(x2, x1),当x2 > x1 时返回true,所以从小到大排序
for (size_t i = 0; i < v.size(); i++)
{
cout << v[i] <<endl;
}
}
Boost.Ref
通常与 Boost.Bind 一起使用
提供了两个函数 - boost::ref()
和 boost::cref()
- 定义于 boost/ref.hpp
如果bind 的函数有引用类型的参数,那么需要Boost.Ref 来对该位置参数特殊处理,因为 boost::bind 会复制它的参数。
简单使用
#include <boost/bind.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
void add(int i, int j, std::ostream &os)
{
os << i + j << std::endl;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::for_each(v.begin(), v.end(), boost::bind(add, 10, _1, boost::ref(std::cout)));
//std::for_each(v.begin(), v.end(), boost::bind(add, 10, _1, std::cout)); // 错误,因为标准输出对象继承自 'std::ios_base',而这个类的拷贝构造函数是私有的,意味着不允许对std::
cout进行拷贝
}
如果执行上述代码被注释的部分会出错,因为boost::bind 会尝试对std::cout 进行拷贝,但 标准输出对象继承自 'std::ios_base',而这个类的拷贝构造函数是私有的,意味着不允许对std:: cout进行拷贝
Boost.Function
用于封装函数指针, 源码位于:boost/function.hpp
简单使用
#include <boost/function.hpp>
#include <iostream>
using namespace std;
void print(int num)
{
cout << num << endl;
}
void printAddOne(int num)
{
cout << num + 1 << endl;
}
int main()
{
boost::function<void (int)> f;
f = print;
f(10);
f = printAddOne;
f(10);
}
如上定义了一个指向“参数为int,返回void的函数”的函数指针f。通过用符合条件的函数对其赋值,然后将其作为函数般调用。
如果 f 未赋予一个函数而被调用,则会抛出一个 boost::bad_function_call
异常。
#include <boost/function.hpp>
#include <iostream>
using namespace std;
int main()
{
boost::function<void (int)> f;
try
{
if (f.empty())
{
cout << "f is empty" << endl;
}
if (!f) // operator bool()
{
cout << "f is null" << endl;
}
f(1);
}
catch(boost::bad_function_call& e)
{
cout << e.what() << endl;
}
}
输出:
f is empty
f is null
call to empty boost::function
绑定类成员函数
#include <boost/function.hpp>
#include <iostream>
using namespace std;
class A
{
public:
void print(std::ostream& os)
{
os << "success" << endl;
}
};
int main()
{
boost::function<void (A*, std::ostream&)> f;
A a;
f = &A::print;
f(&a, boost::ref(std::cout));
}
对于这种定义,函数指针模板的第一个参数必须是成员函数所属类的指针类型,后面是函数的参数列表。因为要传递std::cout 的引用,所以用了boost::ref。
Boost.Lambda
用简洁的语法表达一个函数,令源代码更为紧凑
简单使用
#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/lambda/if.hpp>
void print(int i)
{
std::cout << i << std::endl;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::for_each(v.begin(), v.end(), print);
std::for_each(v.begin(), v.end(), std::cout << boost::lambda::_1 << "\n");
}
上述代码,print 只是实现了输出功能,如果可以在 std::for_each()
算法里面直接定义它的话,会更为方便,既能省去一个函数定义,又能使代码更为紧凑,使得算法与负责数据输出的函数不是局部性分离的
Boost.Lambda 定义了三个占位符,名为 _1, _2 和 _3。这些占位符是定义在单独的名字空间的。 例如代码第一个占位符是通过 boost::lambda::_1 来引用的。 使用时需包含头文件 boost/lambda/lambda.hpp
。
虽然 Boost.Lambda 非常强大,但也有一些缺点。 要在以上例子中插入换行的话,必须用 "\n" 来替代 std::endl
才能成功编译。 因为一元 std::endl
模板函数所要求的类型不同于 lambda 函数 std::cout << boost::lambda::_1
的函数,所以在此不能使用它。
加入if判断条件
#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/lambda/if.hpp>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
//std::for_each(v.begin(), v.end(), boost::lambda::if_then(boost::lambda::_1 > 1, std::cout << boost::lambda::_1 << std::endl)); // 这里会报错
std::for_each(v.begin(), v.end(), boost::lambda::if_then(boost::lambda::_1 > 1, std::cout << boost::lambda::_1 << "\n"));
}
只输出大于1的值
除了 boost::lambda::if_then()
, Boost.Lambda 还提供了
boost::lambda::if_then_else()
和 boost::lambda::if_then_else_return()
模板函数
lambda函数整体复杂度越高,可读性越低,实际使用应该权衡两者。
参考: