1. STL中的priority_queue模板定义:
template < class T, class Container = vector,
class Compare = less > class priority_queue;
//第一个参数是元素类型;
//第二个参数是保存数据的容器,通常是数组类的,比如vector、deque,默认用vector
//第三个参数是元素比较方式,默认用<,缺省时采用内建类型的比较方式。用户可自定义仿函数
priority_queue利用大数堆或者小数堆实现,它是一个基于基本序列容器构建的适配器(queue和stack也是)。priority_queue放置元素时不会去重(因为第二个参数的容器不能保证元素的唯一性)。
priority_queue 调用STL里的 make_heap(), pop_heap(), push_heap() 算法实现,也算是堆的另外一种形式。hit this
2. 仿函数(functor):
仿函数是通过重载()运算符模拟函数行为的类(或者是结构体),也就是仿函数并不是真正意义上的函数,而是通过类对象的调用来模拟函数的行为。之前在自定义set的比较函数中实现了一个简单的仿函数,当时还不太理解,它是STL六大组件(容器,迭代器,算法,仿函数,配置器?,配接器?)之一,仿函数拓展了算法的功能,几乎所有的算法都支持仿函数版本。
仿函数,又叫函数对象(《数据结构与算法分析 C++描述》),函数对象调用时不是使用函数名来调用函数,而是使用操作符重载。函数对象提供两大优势的函数调用。第一个是函数对象可以包含状态,第二是函数对象属于类型并可用作模板参数。具体方法是,定义一个包含零个数据和一个成员函数的类(视情况而定,下面的例子是这样的,数据成员通常用来表征状态,这也正是仿函数的魅力所在),然后传递这个类的实例,从效果上看,通过将其在对象中实现了的函数的传递。该对象通常称为函数对象(function object)。例如:
template
const Object & findMax(const vector
c++的函数对象有一些奇特的语法,函数对象调用时不是使用函数名来调用函数,而是使用操作符()的重载。即不是使用函数isLessThan,而是使用operator(),当调用operator()时,cmp.operator()(x,y)可以缩写为cmp(x,y),换句话说,这看起来就像是函数调用,因此,operator()被称为函数调用操作符(function call operator),其参数改成更容易理解的isLessThan。
更为晦涩一点的版本是直接重载operator()函数,并把比较在重载的函数中做,返回bool值。也就是自定义set的比较函数中的形式。
3. Next,《STL,标准模板库》p123以及第8章对仿函数的特点的用法进行了详细的介绍:(下面自己总结的很烂,感兴趣的话还是直接看书吧)
仿函数的优势:1)smart functions。仿函数可拥有成员函数和成员变量,也就是仿函数可以拥有状态信息,通过不同的状态来表征不同的行为,更加灵活。在同一时间里由某个仿函数所代表的单一函数,可能有不同的状态,这在一般函数中是不可能的;2)每个仿函数都有自己的型别,这对于“利用template实现泛型编程”是一个卓越的贡献。也就是说从本质来看,每一个仿函数都属于一种类型,这可以在定义模板时将其作为模板参数,而这是普通函数做不到的。3)仿函数通常比一般函数快一些。由于template通常在编译期间就已确定,所以传入一个仿函数可能会获得更好的性能。
带有状态的仿函数的使用方法:
// 1. 构造一个带有数据成员theValue的AddValue类(用作函数对象)
// 2. 举个例子
for_each(a.begin(), a.end(), AddValue(10));
// 说明,其中的AddValue(10)生成一个AddValue对象,并以10作为初值,AddValue构造函数将这个值保存在成员theValue
多状态的优势:
// 下面看“一个函数,两个状态”
AddValue addx(x);
AddValue addy(y);
// ... ...
for_each(a.begin(), a.end(), addx);
for_each(a.begin(), a.end(), addy);
// 上述两个表达式分别调用了不同状态的仿函数,very cool!
仿函数通常是通过by value方式调用,每次调用不会改变其内部状态。但是也可以使用by reference方式调用,这样的话可以改变其内部状态
IntSequence seq(1); //声明一个仿函数,将内部数据成员初始化为1.
generate<... , int, IntSequence&> (a, int, seq); //调用函数generate时,将其template参数明白加以标示(将IntSequence重写为IntSequence&),下次再使用seq时,其内部数据成员的值已经改变(该generate函数结束时的值)
另外,for_each()可以返回其使用的仿函数的最终状态:
AddValue av = for_each(a.begin(), a.end(), addx);
此时如果AddValue中定义了一些打印信息的函数,可以直接调用av.print_func()打印出信息确认。
参考:msdn 函数对象, and使用lambda函数,函数对象和受限函数