仿函数(functor),就是使一个类或类模板的使用看上去象一个函数。其实现就是类或类模板中对operator()进行重载,这个类或类模板就有了类似函数的行为。仿函数是智能型函数就好比智能指针的行为像指针,其就可看作是一个指针。但是智能指针是定义的一个类对象,所以在具备指针功能的同时也有其他的能力。仿函数的能力也可以超越operator()。因为仿函数可以拥有成员函数和成员变量,这意味着仿函数拥有状态。另一个好处是可以在执行期初始化它们。
加法:plus<T>;减法:minus<T>;乘法:multiplies<T>;除法:divides<T>;求余:modulus<T>;否定:negate<T>
等于:equal_to<T>;不等于:not_equal_to<T>;大于:greater<T>;大于等于:greater_equal<T>;小于:less<T>;小于等于:less_equal<T>
除了否定为一元,其他都为二元仿函数。与:logical_and<T>;或:logical_or<T>;否:logical_not<T>
下面是一个哈夫曼编码示例,遇到了需要对一个文件中的所有字符进行权重计算以创建每个字符的最终编码的过程,这其中有一个步骤是需要遍历已有的字符权重表以查找当前从文件中取得的字符是否已经存在于该表中,如果存在就将该表中的该字符权重加一,如不存在则需要新建一个存储 node 以存储该字符,并将该 node 结构添加到已有的权重表中。考虑到需要在权重表中进行字符查找以及之后创建 Huffman Tree 时可能需要对该表各项进行排序所以选用 vector<Node>作为存储容器,查找及排序可以使用 algorithm 头文件当中的 sort 和 find 算法。
1 #include <iostream> 2 #include <fstream> 3 #include <string> 4 #include <vector> 5 #include <algorithm> 6 #include <functional>//for bind2nd func; 7 8 #ifndef HUFFMAN_H 9 #define HUFFMAN_H 10 11 using namespace std; 12 13 class Huffman 14 { 15 public: 16 Huffman(void); 17 //huffman(File file, File srcTable); 18 void encode(const string& file); 19 void decode(const string& file, const string& srcTable) const; 20 ~Huffman(); 21 private: 22 //table node 23 typedef struct 24 { 25 char letter; 26 int level; 27 int parent; 28 int direction;//-1 for no parent, 0 for left, 1 right; 29 }Node; 30 vector<Node> nodeTable;//can be sorted; 31 32 //仿函数,用于find_if,侦测字符是否已经存在; 33 //template <typename T1, typename T2> 34 class Comparer : public binary_function<Node, char, bool> 35 { 36 public: 37 Comparer(const char ch):_ch(ch){}; 38 39 const bool operator()(const vector<Node>::value_type& node, char ch) const 40 { 41 return node.letter == ch; 42 } 43 44 private: 45 char _ch; 46 }; 47 }; 48 49 #endif
1 #include "Huffman.h" 2 3 Huffman::Huffman(void) 4 { 5 //dummany; 6 } 7 8 void Huffman::encode(const string& file) 9 { 10 ifstream fin; 11 fin.open(file.c_str()); 12 char ch; 13 while(fin.get(ch)) 14 { 15 if (nodeTable.size() != 0) 16 { 17 //仿函数 18 vector<Node>::iterator result = find_if(nodeTable.begin(),nodeTable.end(),bind2nd(Comparer(ch), ch)); 19 20 if (result == nodeTable.end()) 21 { 22 Node* node = new Node; 23 node->letter = ch; 24 node->level = 1; 25 node->parent = 0; 26 node->direction = -1; 27 } 28 else 29 { 30 result->level += 1; 31 } 32 } 33 else 34 { 35 Node* node = new Node; 36 node->letter = ch; 37 node->level = 1; 38 node->parent = 0; 39 node->direction = -1; 40 } 41 } 42 fin.close(); 43 44 45 //huffman tree; 46 47 } 48 49 void Huffman::decode(const string& file, const string& srcTable) const 50 { 51 //dummany; 52 } 53 54 Huffman::~Huffman(void) 55 { 56 //dummany; 57 }
此处仿函数调用过程是这样的:find_if(nodeTable.begin(), nodeTable.end(), Comparer(ch))中 Comparer(ch)只是创建了 Comparer 类的匿名方法,重载的 operator() 真正的调用是在接下来将要看到的 find_if 模板函数的这一句 pred(*first);代码中不使用 find 而使用 find_if 是因为需要进行查找的不是 prime type 而是自行编写的符合类型,find_if 的函数原型参考如下,从原型中可以看到第一个参数是以默认的方式进行的:
1 template<class InputIterator, class Predicate> 2 InputIterator find_if ( InputIterator first, InputIterator last, Predicate pred ) 3 { 4 for ( ; first!=last ; first++ ) if ( pred(*first) ) break; 5 return first; 6 }
bind2nd 函数的作用是将 二元算子(binary functor, bf) 转化为一元算子(unary functor, uf) 还有一个类似的 bind1st ,使用时需要包含 functional 头文件;进行比较的仿函数需要继承 binary_functor<typename T1,typename T2,typename T3>,T3 一般为 bool 值, binary_functor 原型如下:
1 template<class Arg1,class Arg2,class Result> 2 struct binary_function 3 { 4 typedef Arg1 first_argument_type; 5 typedef Arg2 second_argument_type; 6 typedef Result result_type; 7 };
这里使用的是 bind2nd 直接将得到的 char 参数 bind 到 Comparer 仿函数中,当然可以使用直接传参数到 Comparer 仿函数中人的方法,从 Huffman.h 和 Huffman.cpp 的注释中可以看到存在不同的可行方法。