boost------function的使用(Boost程序库完全开发指南)读书笔记
function是一个函数对象的“容器”,概念上像是c/c++中函数指针类型的泛化,是一种“智能函数指针”。它以对象的形式封装了原始的函数指针或函数对象,能够容纳任意符合函数签名的可调用对象。
因此,它可以被用于回调机制,暂时保管函数或函数对象,在之后需要的时机再调用,使回调机制拥有更多的弹性。
1、function的声明
比如使用function<int(doublea, double b)> func;
这就是声明了一个function对象,返回值为int,有两个参数都为double
2、操作函数
无参的构造函数或者传入空指针构造将创建一个空的function对象,不持有任何可调物,调用空的function对象将抛出bad_function_call异常,因此在使用function前最后检测一下它的有效性。
可以用empty()测试function是否为空,或者用重载操作符operaor!来测试。function对象也可以在一个bool上下文中直接测试它是否为空,他是类型安全的。
3、比较操作
function重载了比较操作符operator==和operator!=,可以与被包装的函数或函数对象进行比较。如果function存储的是函数指针,那么比较相当于:
function.target<Function>() == func_pointer
例如
function<int(int a, int b)> func(f);
assert(func == f);
如果function存储的是函数对象,那么要求函数对象必须重载了operator==,是可比较的。
两个function对象不能使用==或!=直接比较,这是特意的。因为function存在到bool的隐式转换,function定义了两个function对象的operator==但没有实现,企图比较两个function对象会导致编译错误。
4、用法
#include "stdafx.h"
#include "boost/utility/result_of.hpp"
#include "boost/typeof/typeof.hpp"
#include "boost/assign.hpp"
#include "boost/ref.hpp"
#include "boost/bind.hpp"
#include "boost/function.hpp"
#include "iostream"
using namespace std; int f(int a, int b)
{
return (a + b);
} int _tmain(int argc, _TCHAR* argv[])
{
boost::function<int(int a, int b)> func;
func = f; if (func)
{
cout << func(10, 20) << endl;
} func = 0; assert(!func.empty()); return 0;
}
function这种能够容纳任意可调用对象的能力是非常重要的,在编写泛型代码的时候尤其有用,它使我们能够接受任意的函数或函数对象,增加程序的灵活性。
与原始的函数指针相比,function对象的体积要稍微大一点(3个指针的大小),速度要稍微慢一点(10%左右的性能差距),但这与它带给程序的巨大好处相比是无足轻重的。
只要函数签名式一致,function也可以存储成员函数和函数对象,或者bind表达式的结果:
#include "stdafx.h"
#include "boost/utility/result_of.hpp"
#include "boost/typeof/typeof.hpp"
#include "boost/assign.hpp"
#include "boost/ref.hpp"
#include "boost/bind.hpp"
#include "boost/function.hpp"
#include "iostream"
using namespace std; struct DemoClass
{
int add(int a, int b)
{
return (a + b);
} // int operator()(int a, int b) const
// {
// return (a + b);
// }
}; int _tmain(int argc, _TCHAR* argv[])
{
DemoClass democlass; boost::function<int(DemoClass&, int, int)> func;
// func = boost::bind(&DemoClass::add, _1, _2, _3);
func = boost::bind(&DemoClass::add, democlass, _2, _3); cout << func(democlass, 10, 20) << endl; return 0;
}
5、使用ref库
function使用拷贝语义保存参数,当参数很大时拷贝的代价往往很高, 或者有时候不能拷贝参数,这时就使用ref库。
function并不要求ref库提供operator(),因为它能够自动识别包装类reference_wraooer<T>,并调用get()方法获得被包装的对象:
#include "stdafx.h"
#include "boost/utility/result_of.hpp"
#include "boost/typeof/typeof.hpp"
#include "boost/assign.hpp"
#include "boost/ref.hpp"
#include "boost/bind.hpp"
#include "boost/function.hpp"
#include "iostream"
using namespace std; struct DemoClass
{
// int add(int a, int b)
// {
// return (a + b);
// } int operator()(int a, int b) const
{
return (a + b);
}
}; int _tmain(int argc, _TCHAR* argv[])
{
DemoClass democlass;
boost::function<int(int x, int y)> func;
func = cref(democlass); // 使用cref()函数包装常对象的引用
cout << func(10, 20) << endl; // 调用被引用的对象 return 0;
}
6、用于回调
function可以容纳任意符合函数签名式的可调用物,因此它非常适合代替函数指针,存储用于回调的函数,而且它的强大功能会使代码更灵活、富有弹性。
看看下面的例子:
#include "stdafx.h"
#include "boost/utility/result_of.hpp"
#include "boost/typeof/typeof.hpp"
#include "boost/assign.hpp"
#include "boost/ref.hpp"
#include "boost/bind.hpp"
#include "boost/function.hpp"
#include "iostream"
using namespace std; class DemoClass
{
public:
// int add(int a, int b)
// {
// return (a + b);
// }
DemoClass(int i) : n(i)
{ } int operator()(int a, int b) const
{
return (a + b);
} template<typename CallBack>
void accept(CallBack f)
{
func_ = f;
} void run()
{
func_(n);
}
private:
typedef boost::function<void(int)> func_t;
func_t func_;
int n;
}; void call_back_func(int i)
{
cout << "call back func : ";
cout << i * 2 << endl;
} int _tmain(int argc, _TCHAR* argv[])
{
DemoClass dc(19);
dc.accept(call_back_func);
dc.run(); return 0;
}
这就是一个简单使用function作为函数回调的例子。
DemoClass使用模板函数accept()接受回调函数。之所以使用模板函数是因为这种形式更加灵活,用户可以在不知道也不关心内部存储形式的情况下传递任何可调用对象,包括函数指针和函数对象。
使用普通的C函数进行回调并不能体现function的好处,下面来看一个带状态的函数对象,并使用ref库传递引用:
#include "stdafx.h"
#include "boost/utility/result_of.hpp"
#include "boost/typeof/typeof.hpp"
#include "boost/assign.hpp"
#include "boost/ref.hpp"
#include "boost/bind.hpp"
#include "boost/function.hpp"
#include "iostream"
using namespace std; class DemoClass
{
public:
DemoClass(int i) : n(i)
{ } template<typename CallBack>
void accept(CallBack f)
{
func_ = f;
} void run()
{
func_(n);
}
private:
typedef boost::function<void(int)> func_t;
func_t func_;
int n;
}; class call_back_obj
{
public:
call_back_obj(int x) : x_(x)
{ } void operator()(int i)
{
cout << "call_back_obj : " << i * x_++ << endl;
} private:
int x_; // 内部状态
}; int _tmain(int argc, _TCHAR* argv[])
{
DemoClass dc(10);
call_back_obj cbo(2); dc.accept(boost::ref(cbo));
dc.run();
dc.run(); return 0;
}
DemoClass因为使用了function作为内部可调用物的存储,因此不用做任何改变,即可接受函数指针也可以接受函数对象,给用户以最大的方便。
function还可以搭配bind库,把bind表达式作为回调函数,可以接受类成员函数,或者把不符合函数签名式的函数bind变为可接受的形式,下面是一个例子:
#include "stdafx.h"
#include "boost/utility/result_of.hpp"
#include "boost/typeof/typeof.hpp"
#include "boost/assign.hpp"
#include "boost/ref.hpp"
#include "boost/bind.hpp"
#include "boost/function.hpp"
#include "iostream"
using namespace std; class DemoClass
{
public:
DemoClass(int i) : n(i)
{ } template<typename CallBack>
void accept(CallBack f)
{
func_ = f;
} void run()
{
func_(n);
}
private:
typedef boost::function<void(int)> func_t;
func_t func_;
int n;
}; class call_back_factory
{
public:
void call_back_func1(int i)
{
cout << "call_back_func1 : " << i * 2 << endl;
}
void call_back_func2(int i, int j)
{
cout << "call_back_func2 : " << i * j * 2 << endl;
}
}; int _tmain(int argc, _TCHAR* argv[])
{
DemoClass dc(10);
call_back_factory cbf;
dc.accept(boost::bind(&call_back_factory::call_back_func1, boost::ref(cbf), _1));
dc.run(); dc.accept(boost::bind(&call_back_factory::call_back_func2, boost::ref(cbf), _1, 2));
dc.run(); return 0;
}
通过以上的示例代码,可以看到function用于回调的好处,它无需改变回调的接口就可以解耦客户代码,是客户代码不必绑死在一种回调形式上,进而可以持续演化。而function始终能够保证与客户代码正确沟通。
boost------function的使用(Boost程序库完全开发指南)读书笔记的更多相关文章
- boost------signals2的使用2(Boost程序库完全开发指南)读书笔记
1.应用于观察者模式 本小节将使用signals2开发一个完整的观察者模式示例程序,用来演示信号/插槽的用法.这个程序将模拟一个日常生活场景:客人按门铃,门铃响,护士开门,婴儿哭闹. Ring.h: ...
- boost------asio库的使用2(Boost程序库完全开发指南)读书笔记
网络通信 asio库支持TCP.UDP.ICMP通信协议,它在名字空间boost::asio::ip里提供了大量的网络通信方面的函数和类,很好地封装了原始的Berkeley Socket Api,展现 ...
- boost------signals2的使用1(Boost程序库完全开发指南)读书笔记
signals2基于Boost的另一个库signals,实现了线程安全的观察者模式.在signals2库中,观察者模式被称为信号/插槽(signals and slots),他是一种函数回调机制,一个 ...
- boost------asio库的使用1(Boost程序库完全开发指南)读书笔记
asio库基于操作系统提供的异步机制,采用前摄器设计模式(Proactor)实现了可移植的异步(或者同步)IO操作,而且并不要求多线程和锁定,有效地避免了多线程编程带来的诸多有害副作用. 目前asio ...
- boost------bind的使用(Boost程序库完全开发指南)读书笔记
bind是c++98标准库中函数适配器bind1st/bind2nd的泛化和增强,可以适配任意的可调用类型,包括函数指针.函数引用.成员函数指针和函数对象. 1.工作原理 bind并不是一个单独的类或 ...
- [转] boost------ref的使用(Boost程序库完全开发指南)读书笔记
http://blog.csdn.net/zengraoli/article/details/9663057 STL和Boost中的算法和函数大量使用了函数对象作为判断式或谓词参数,而这些参数都是传值 ...
- boost------ref的使用(Boost程序库完全开发指南)读书笔记
STL和Boost中的算法和函数大量使用了函数对象作为判断式或谓词参数,而这些参数都是传值语义,算法或函数在内部保修函数对象的拷贝并使用,例如: #include "stdafx.h&quo ...
- node.js开发指南读书笔记(1)
3.1 开始使用Node.js编程 3.1.1 Hello World 将以下源代码保存到helloworld.js文件中 console.log('Hello World!'); console.l ...
- Ngine X 完全开发指南 读书笔记-前言
一开始接触的编程语言是VF,那是一种可视化编程语言,所谓的可视化,就是运行结果能直接看得到的,非常直观,便于调试,适合刚刚接触编程的新人学习.当时学得懵懂,半知半解,就是感觉程序非常神奇,常常几句代码 ...
随机推荐
- 搭建 Win CE6.0 设备开发环境
1.操作系统最好基于Windows XP.Vista.Win7 或以上的版本对ActiveSync软件不支持 2.安装VS2008,以及SP1 (一定要装SP1) 3.安装ActiveSync 4. ...
- ECshop Strict Standards: Only variables should be passed by reference in解决办法
本文章来给各位同学介绍关于ECshop Strict Standards: Only variables should be passed by reference in解决办法,希望此教程 对各位同 ...
- yii 验证器和验证码
http://www.yiiframework.com/doc/api/1.1/CCaptcha http://www.cnblogs.com/analyzer/articles/1673015.ht ...
- mysql select count(filed) 问题(where条件没有数据匹配的话也有数据返回)。
问题: SELECT count(*),user_id FROM tb_rp_logintrace WHERE id=-1 返回结果: count(*), user_id 0 ...
- Android开发UI之常用控件的使用
1.日期选择控件 DatePickerDialog 代码: btnChooseDate=(Button) findViewById(R.id.btnChooseDate); btnChooseDate ...
- mapreduce实现"浏览该商品的人大多数还浏览了"经典应用
输入: 日期 ...cookie id. ...商品id.. xx xx xx 输出: 商品id ...
- 用Remastersys定制自己的Ubuntu安装光盘
这两天因为要做Ubuntu的平台移植,一直在给自己电脑上的Ubuntu系统装各种软件,其间几次将内核破坏,导致不得不重装系统,经过几次痛苦的等待,痛定思痛,决定试一试能不能将自己的Ubuntu系统定制 ...
- 【转】win7与VMware ubuntu虚拟机实现文件共享(最后一定要装open-vm-dkms插件)
原文网址:http://blog.sina.com.cn/s/blog_453b9efb01019hpl.html 一般来说,由于一些特殊的需要,会在Win7系统中利用虚拟机(VMware)安装ubu ...
- sqliteExpert软件使用(创建数据库和表)
sqliteExpert是sqlite数据库的可视化操作软件,通过该软件可以进行可视化的创建数据库以及表,免去了复杂的建表语句.首先在下面地址下载该软件http://www.ddooo.com/sof ...
- SharePoint2010主题和样式揭秘
转:http://www.cnblogs.com/Ryu666/archive/2011/07/28/2119652.html 好久好久没写技术博客了,差点以为技术已经离我远去.但鱼离不开水,我怎能把 ...