boost::bind 学习
最近学习了太多与MacOS与Iphone相关的东西,因为不会有太多人有兴趣,学习的平台又是MacOS,不太喜欢MacOS下的输入法,所以写下来的东西少了很多。
等我学习的东西慢慢的与平台无关的时候,可能可以写下来的东西又会慢慢多起来吧。。。。。不过我想早一批订阅我博客的人应该已经不会再看了,因为已经很少会有程序语言或者C++之类的信息,相关的东西应该都是关于计算机图形,游戏的。或者,早一批订阅我博客的人现在也已经毕业,工作了呢?
对了,这次的主题是boost:bind。在历经了
boost::asio(1)
boost::asio(2)
boost::asio(3)
boost::foreach
boost::function
boost::lambda
boost::serialization(1)
boost::serialization(2)
boost::string_algo
boost::thread
之后,boost常用的很多都学会了,现在自己写点小东西,那是大胆的用大。。。。。。。呵呵,反正自己的东西,就当用来锻炼技术了。在学习boost::signal2的过程中发现自己其实对boost::bind这个将来要进C++标准的库了解还不够多,(在boost::functon中有所提及,也同时学了一点),所以抽了点时间,好好的学习了一下。
Purpose(目的)
原来文档中的purpose完全就是教程了,事实上,bind主要用于改造函数,比如,一个地方需要一个无参的函数,你只有一个以int为参数的函数,并且你知道此时int一直为1就可以了,你怎么办?传统方法,直接实现一个函数,然后以1调用以前的那个int为参数的函数。如下:
void Fun1(int i) {
printf(" %d /n " , i);
}
void FunWeNeed() {
Fun1(1 );
}
int main()
{
FunWeNeed();
return 0 ;
};
当然,这个例子太扯了,我们只需要直接用Fun1(1)调用就可以了,但是bind的目的就是如此,只不过现实中因为各种各样的原因,你的确需要改造函数。再比如下面的情况,你有一个原来写好的函数,接受一个以无参函数为参数,那么,你的Fun1就没有办法派上用场了,那么,传统上,怎么办?如下:
typedef void FunWeNeed_t(void );
void CallFun( FunWeNeed_t f) {
f();
}
void Fun1(int i) {
printf(" %d /n " , i);
}
void FunWeNeed() {
Fun1(1 );
}
int main()
{
// CallFun(Fun1); // this line can't compile
CallFun(FunWeNeed);
return 0 ;
};
Ok,你不得不写新的函数以满足需求,因为你没有简单的办法改变一个函数的参数。事实上,假如你是STL流派的话,那么随着你使用标准库的算法的次数的增加,你会遇到越来越多上面描述的情况,到底很简单,C++是如此的类型安全的语言,它不会加上诸如参数过多就忽略后面参数的胡扯特性。那么,一个算法需要你传进来的是什么形式的函数(或者函数对象),那么你就的怎么做。
去看看,标准库中提供了一大堆多么扯的函数对象吧,less, more,,greater_equal,not1,not2,。。。。。。然后还给了你一堆compose1,compose2........最后附带最恶心的bind1st,bind2nd,事实上,这些东西如此之多,以至于我甚至懒的列举出来,但是事实上我们在项目中用到了多少?简而言之,None!一次也没有,甚至因为很多算法与此相关,我们连那些算法也不用!
为啥C++当年出现了那么多奇怪臃肿无用的设计?可能是,C++标准出现的那个年代,编程技术的发展也就到那个地步吧。。。。。。。。。在C/C++语言中,关于函数的抽象特别的少,原因很简单,因为函数指针太不好用了!(函数抽象也用,但是好像用的最多的是在C语言中无物可用时,不得已的而为之)
记得在哪看过一句话,技术再花哨也没有用,最重要的是足够简单,因为不够简单的技术就很难给人讲解,别人很难理解那么就很难应用。这些C++特性应该算是其中的一例了。
boost中的bind,function ,lambda 就是为此而生的。注意,在tr1中,你就已经可以使用bind和function特性了,这也很可能是将来的C++标准之一。现在boost中的lambda还不够成熟,语法很怪,限制很多,因为,毕竟,boost再强大,仅仅是库啊。。。。。。。。。匿名函数的功能完全值得用语言特性来实现!
上面那个很扯的例子,总的给个bind的解决方案吧。
#include <boost/bind.hpp>
#include <boost/function.hpp>
void CallFun( boost::function<void (void )> f) {
f();
}
void Fun1(int i) {
printf(" %d /n " , i);
}
void FunWeNeed() {
Fun1(1 );
}
int main()
{
CallFun(boost::bind(Fun1, 1 )); // this line can't compile
CallFun(FunWeNeed);
return 0 ;
};
需要注意的是,此时不能再使用函数指针了,bind的天生合作伙伴是function,而function是支持函数指针的(如上例所示) 。目的将的很多了,下面看看用法吧(不是什么问题)。
普通函数
最有意思的是,你甚至能用bind来扩充原有函数的参数,见下例:
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
using namespace std;
using namespace boost;
void f(int a, int b)
{
cout <<"Argument 1 is " <<a <<endl;
}
void g(int a, int b, int c)
{
cout <<"sum is " <<a+b+c <<endl;
cout <<"arg 1: " <<a <<endl;
cout <<"arg 2: " <<b <<endl;
cout <<"arg 3: " <<c <<endl;
cout <<"---------------------------" <<endl;
}
int main()
{
function<void (int ,int )> f1= bind(f, _2, _1); // 调整参数1,2的位置
f1(1 , 2 );
function<void (int )> sum1 = bind(g, _1, _1, _1); // 3个参数变1个
sum1(10 );
function<void (int , int )> sum2 = bind(g, _2, _2, _2); // 3个参数变2个,仅用一个
sum2(10 , 20 );
function<void (int , int , int )> sum3 = bind(g, _3, _3, _3); // 3个参数还是3个,但是仅用1个
sum3(10 , 20 , 30 );
function<void (int , int , int , int )> sum4 = bind(g, _4, _4, _4); // 3个参数变4个,但是仅用1个
sum4(10 , 20 , 30 , 40 );
return 0 ;
};
输出结果:
Argument 1 is 2
sum is 30
arg 1: 10
arg 2: 10
arg 3: 10
---------------------------
sum is 60
arg 1: 20
arg 2: 20
arg 3: 20
---------------------------
sum is 90
arg 1: 30
arg 2: 30
arg 3: 30
---------------------------
sum is 120
arg 1: 40
arg 2: 40
arg 3: 40
---------------------------
函数对象
注意用法中很重要的一条:通常情况下,生成的函数对象的 operator() 的返回类型必须显式指定(没有 typeof 操作符,返回类型无法推导)。(来自Boost文档)
#include <boost/bind.hpp>
#include <boost/function.hpp>
using namespace std;
using namespace boost;
struct F
{
int operator ()(int a, int b) { return a - b; }
bool operator ()(long a, long b) { return a == b; }
};
int main()
{
F f;
int x = 104 ;
function< int (int ) > fun1 = bind<int >(f, _1, _1); // f(x, x), i.e. zero
cout <<fun1(1 );
function< bool (long ) > fun2 = bind<bool >(f, _1, _1); // f(x, x), i.e. zero
cout <<fun2(1 );
return 0 ;
};
其他的也就很简单了。
成员指针
例子来源于boost文档。
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/smart_ptr.hpp>
using namespace std;
using namespace boost;
struct X
{
void f(int a) {
cout <<a <<endl;
}
};
int main()
{
X x;
shared_ptr<X> p(new X);
int i = 1 ;
bind(&X::f, ref(x), _1)(i); // x.f(i)
bind(&X::f, &x, _1)(i); //(&x)->f(i)
bind(&X::f, x, _1)(i); // (internal copy of x).f(i)
bind(&X::f, p, _1)(i); // (internal copy of p)->f(i)
return 0 ;
}
可见bind的强大,支持自己拷贝需要的对象,支持引用,甚至,支持智能指针。
最后一个例子,结合标准库容器及算法的例子,这才是展示bind的强大的地方。
还是来自于boost文档。
class image;
class animation
{
public :
void advance(int ms);
bool inactive() const ;
void render(image & target) const ;
};
std::vector<animation> anims;
template <class C, class P> void erase_if(C & c, P pred)
{
c.erase(std::remove_if(c.begin(), c.end(), pred), c.end());
}
void update(int ms)
{
std::for_each(anims.begin(), anims.end(), boost::bind(&animation::advance, _1, ms));
erase_if(anims, boost::mem_fn(&animation::inactive));
}
void render(image & target)
{
std::for_each(anims.begin(), anims.end(), boost::bind(&animation::render, _1, boost::ref(target)));
}
例子展示了erase_if,for_each算法中使用bind的方法,当然,实际中,假如是你的游戏引擎中的update,render函数,碰到上述需求或者类似代码实现是很正常的,但是,你会放心的仅仅为了简化一些代码,然后将如此性能相关的位置,直接交给bind吗?
boost::bind 学习的更多相关文章
- boost库学习随记六:使用同步定时器、异步定时器、bind、成员函数回调处理、多线程的同步处理示例等
一.使用同步定时器 这个示例程序通过展示如何在一个定时器执行一个阻塞等待. //makefile #-------------------------------------------------- ...
- boost asio 学习(二)了解boost::bind
2.了解boost::bind使用boost::bind封装一个函数,考虑以下例子示例2a #include <iostream> #include <boost/bind.hpp& ...
- boost asio 学习(九) boost::asio 网络封装
http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio?pg=10 9. A ...
- boost asio 学习(八) 网络基础 二进制写发送和接收
http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio?pg=9 8. Net ...
- boost asio 学习(七) 网络基础 连接器和接收器(TCP示例)
http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio?pg=8 7. Net ...
- boost asio 学习(六) 定时器
http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio?pg=7 6 定时器 ...
- BOOST ASIO 学习专贴
本文已于20170903更新完毕,所有boost asio 代码均为本人手抄.编译器为vs2013,并且所有代码已经上传,本文下方可下载源码 为了学习boost asio库,我是从boost的官方bo ...
- 1,Boost -> Bind
#include <boost/bind.hpp> #include <boost/shared_ptr.hpp> #include <iostream> usin ...
- boost库学习之开篇
本系列文章使用boost_1.58.0版本. 一.欢迎使用boost C++库 boost致力于提供一个免费的.便携的源代码级的库. 我们重视那些与C++标准一起工作良好的库.boost库将要成为一个 ...
随机推荐
- css文字属性
font-family- css字体:设定时,需考虑浏览器中有无该字体. 比如说“黑体” “微软雅黑” font-size -css字体大小: 注意度量html单位.例如:font-size:18p ...
- JS中Date.parse()和Date.UTC()返回值不一致
Date.parse() 方法解析一个表示某个日期的字符串,并返回从1970-1-1 00:00:00 UTC 到该日期对象(该日期对象的UTC时间)的毫秒数,如果该字符串无法识别,或者一些情况下,包 ...
- html History API
History api 兼容性支持一下浏览器 为什么要使用History API 在AJAX给我们带来提高用户体验.减少HTTP连接数等好处的同时,也渐渐显露出一些不足之处,比如: 1.页面全是用aj ...
- Flutter自定义标题栏之处理状态栏高度
App在很多情况下由于各种需求需要自定义标题栏,而在能够构建Android和IOS应用的Flutter中,如果不在Scaffold中使用AppBar会发现默认是沉浸式. 猜想:我们使用自定义标题栏好像 ...
- Date()对象的设置与解析
怎么获取当前时间? 怎么给Date对象设置特定时间? 将Date对象解析为毫秒数? 将Date对象解析为日月年?获取小时/分钟/秒? 直接new Date()新建对象,可以获取当前时间的Date对象: ...
- CCSUOJ评测系统——第一次scrum冲刺
1.第一次冲刺任务安排 对Github上的HUSTOJ开源项目进行Fork,搭建基本环境 2.用户需求 ①基本功能显示在首页 ②能够提交题目并判题,并对自己所提交的题目正确性进行反馈,能够查看自己提交 ...
- zabbix系列之八——安装后配置三Triggers
1Triggers(触发器) 描述 详细 备注 术语描述 1)触发器是评估监控项采集的数据的逻辑表达式,代表了当前系统状态. 2)触发器可定义一个什么数据是可接受的阈值,因此,如果接收的数据超过了可接 ...
- C++虚函数原理
类中的成员函数分为静态成员函数和非静态成员函数,而非静态成员函数又分为普通函数和虚函数. Q: 为什么使用虚函数 A: 使用虚函数,我们可以获得良好的可扩展性.在一个设计比较好的面向对象程序中,大多数 ...
- jsp 页面间传递参数
JSP页面间传递参数是经常需要使用到的功能,有时还需要多个JSP页面间传递参数.下面介绍一下实现的方法. (1)直接在URL请求后添加 如:< a href="thexuan.jsp? ...
- iOS中block类型大全
iOS中block类型大全 typedef的block 作为属性的block 作为变量的block 作为方法变量入参的block 作为方法参数的block 无名block 内联函数的block 递归调 ...