当前位置:开发工具->Boost ->Boost简单学习——函数对象Boost.Bind

原创版权标志Boost简单学习——函数对象Boost.Bind

作者:烫烫烫烫烫烫烫烫  发表时间:2015-11-19  阅读:
[摘要] 这次主要介绍的是函数对象,可能称为“高阶函数”更为适合。它实际上是指那些可以被传入到其它函数或是从其它函数返回的一类函数,在C++中高阶函数是被实现为函数对象的。本文将会介绍几个用于处理函数对象的Boost C++库。 其中,Boost.Bind可替换来自C++标准的著名的 std::bind1st() 和 std::bind2nd() 函数,而 Boost.Function则提供了一个用于封装函数指针的类。 最后,Boost.Lambda则引入了一种创建匿名函数的方法。

   Boost.Bind简化了由C++标准中的std::bind1st和std::bind2nd 模板函数所提供的一个机制:将这些函数与几乎不限数量的参数一起使用,就可以得到指定签名的函数。这种情形的一个最好的例子就是在C++标准中定义的多个不同算法。

 #include <iostream> 
 #include <vector> 
 #include <algorithm> 
 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要求它的第三个参数是一个仅接受正好一个参数的函数或函数对象。如果std::for_each被执行,指定容器中的所有元素将按顺序被传入print函数。但是,如果要使用一个具有不同签名的函数的话,事情就复杂了。如果要传入的是以下函数add,它要将一个常数值加至容器中的每个元素上,并显示结果。

 void add(int i, int j) 
 { 
 std::cout << i + j << std::endl; 
 } 

    由于std::for_each()要求的是仅接受一个参数的函数,所以不能直接传入add()函数,必须要修改源码。

#include <iostream> 

 #include <vector> 

 #include <algorithm> 

 #include <functional> 

 class add 

 : public std::binary_function<int, int, void> 

 { 

 public: 

 void operator()(int i, int j) const 

 { 

 std::cout << 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(), std::bind1st(add(), 10)); 

 } 

   以上程序将值10加至容器v的每个元素之上,并使用标准输出流显示结果。源代码必须作出大幅的修改,以实现此功能:add()函数已被转换为一个派生自std::binary_function的函数对象。

   Boost.Bind简化了不同函数之间的绑定。它只包含一个boost::bind()模板函数,定义于boost/bind.hpp中。使用这个函数,可以如下实现以上例子:

 #include <boost/bind.hpp> 
 #include <iostream> 
 #include <vector> 
 #include <algorithm> 
 void add(int i, int j) 
 { 
 std::cout << 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)); 

 } 

    像add这样的函数不再需要为了要用于std::for_each而转换为函数对象。使用 boost::bind,该函数可以忽略其第一个参数而使用。因为add函数要求两个参数,两个参数都必须传递给boost::bind。其中第一个参数是常数值10,而第二个参数则是一个比较奇怪的_1。

   _1 被称为占位符(placeholder),定义于Boost.Bind。除了_1,Boost.Bind还定义了_2 和_3。通过使用这些占位符,boost::bind可以变为一元、二元或三元的函数。对于_1, boost::bind变成了一个一元函数。这是必需的,因为 std::for_each正是要求一个一元函数作为其第三个参数。

   当这个程序执行时,std::for_each对容器v中的第一个元素调用该一元函数。元素的值通过占位符_1 传入到一元函数中。这个占位符和常数值被进一步传递到add函数。通过使用这种机制,std::for_each只看到了由boost::bind所定义的一元函数。而boost::bind本身则只是调用了另一个函数,并将常数值或占位符作为参数传入给它。

   下面这个例子通过boost::bind定义了一个二元函数,用于std::sort算法,该算法要求一个二元函数作为其第三个参数。 

#include <boost/bind.hpp> 
 #include <vector> 
 #include <algorithm> 
 bool compare(int i, int j) 
 { 
 return i > j; 
 } 
 int main() 
 { 
 std::vector<int> v; 
 v.push_back(1); 
 v.push_back(3); 
 v.push_back(2); 
 std::sort(v.begin(), v.end(), boost::bind(compare, _1, _2)); 

 } 


   因为使用了两个占位符_1 和_2,所以boost::bind()定义了一个二元函数。 std::sort()算法以容器 v 的两个元素来调用该函数,并根据返回值来对容器进行排序。基于compare()函数的定义,容器将被按降序排列。

   但是,由于compare()本身就是一个二元函数,所以使用boost::bind()确是多余的。

#include <boost/bind.hpp> 
 #include <vector> 
 #include <algorithm> 
 bool compare(int i, int j) 
 { 
 return i > j; 
 } 
 int main() 
 { 

 std::vector<int> v; 

 v.push_back(1); 

 v.push_back(3); 

 v.push_back(2); 

 std::sort(v.begin(), v.end(), compare); 

 } 


   不过使用boost::bind()还是有意义的。例如,如果容器要按升序排列而又不能修改 compare()函数的定义。

 #include <boost/bind.hpp> 
 #include <vector> 
 #include <algorithm> 
 bool compare(int i, int j) 
 { 
 return i > j; 
 } 
 
 int main() 

 { 

 std::vector<int> v; 

 v.push_back(1); 

 v.push_back(3); 

 v.push_back(2); 

 std::sort(v.begin(), v.end(), boost::bind(compare, _2, _1)); 

 } 

   该例子仅改变了占位符的顺序:_2 被作为第一参数传递,而 _1 则被作为第二参数传递至 compare(),这样即可改变排序的顺序。


文章来源:C++技术网原创文章版权为网站和作者共同所有,会员文章禁止转载。非会员文章转载做好本文超链接即表示授权转载。通过文章下面的分享按钮可以自由分享所有文章。

返回顶部

在线提问
问题标题:
问题描述:(简陋的描述会导致问题被最后回答、没有针对性回答甚至无法解答。请确保问题描述的足够清楚。)

弹幕群聊(QQ群:372130111)

弹幕