仿函数、仿函数类、函数等
条款38:把仿函数类设计为用于值传递
STL中的习惯是当传给函数和从函数返回时函数对象也是值传递的(也就是拷贝)。最好的证据是标准的for_each声明,这个算法通过值传递获取和返回函数对象:
template Function // 注意值返回
for_each(InputIterator first, InputIterator last, Function f); // 注意值传递
条款39:用纯函数做判断式
先介绍两个概念–“纯函数”与“判别式”:
纯函数是返回值只依赖于参数的函数。如果f是一个纯函数,x和y是对象,f(x, y)的返回值仅当x或y的值改变的时候才会改变。
判断式是返回bool(或者其他可以隐式转化为bool的东西)。判断式在STL中广泛使用。标准关联容器的比较函数是判断式,判断式函数常常作为参数传递给算法,比如find_if和多种排序算法。
判断式类是仿函数类,它的operator()函数是一个判断式,也就是,它的operator()返回true或false(或其他可以隐式转换到true或false的东西)。
重要结论:判断式函数必须是纯函数
条款41:了解使用ptr_fun、mem_fun和mem_fun_ref的原因
假设有一个可以测试Widget的函数,
void test(Widget& w); // 测试w,如果没通就标记为“failed”
此外,有一个Widget的容器:
vector vw; // vw容纳Widget
要测试vw中的每个Widget,显然可以这么使用for_each:
for_each(vw.begin(), vw.end(), test); // 调用#1(可以编译)
但如果test是Widget的成员函数而不是非成员函数,也就是说,Widget支持自我测试:
class Widget {
public:
void test(); // 进行自我测试;如果没通过就把*this标记为“failed”
};
如果使用for_each对vw中的每个对象调用Widget::test:
for_each(vw.begin(), vw.end(),&Widget::test); // 调用#2(不能编译)
解释:STL里的一个普遍习惯:函数和函数对象总使用非成员函数的语法形式调用,而不直接支持成员函数的调用
为了解决这个问题,mem_fun和mem_fun_ref便提出来了:
list lpw; // 同上
...
for_each(lpw.begin(), lpw.end(),mem_fun(&Widget::test)); // 这个现在可以编译了