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,那是一种可视化编程语言,所谓的可视化,就是运行结果能直接看得到的,非常直观,便于调试,适合刚刚接触编程的新人学习.当时学得懵懂,半知半解,就是感觉程序非常神奇,常常几句代码 ...
随机推荐
- Jfinal 入门
Jfinal 入门 IDE----->IDEA 新建项目 新建web项目 添加maven特性 方便导入jar包,不用一个个导入了 配置pom.xml <dependencies> & ...
- net.sf.json日期类型格式化输出
net.sf.json 日期类型格式化输出 Date, Timestamp ; 编写工具类 package cn.jorcen.commons.util; import java.text.DateF ...
- Linux查看用户和组命令
在Linux系统里,我们会经常用Linux查看用户的命令,在这里我们一些命令进行了总结,总共有7个,并做了详细的解释,以便让大家更深入的理解,接下来让我们一起来看看这些命令和具体应用. 一.Linux ...
- Jquery.Validate验证CheckBoxList,RadioButtonList,DropDownList是否选中
http://blog.csdn.net/fox123871/article/details/8108030 <script type="text/javascript"&g ...
- asp.net(c#)有关 Session 操作的几个误区
1. this.Session["username"] = null HttpSessionState 内部使 用 NameObjectCollection 类型的集合对象来存储 ...
- 四大主流云平台对比--CloudStack, Eucalyptus, vCloud Director和OpenStack。
我迟早可能都要进入的领域,提前温习... 还有KVM,ESXI,API,XEN之间的术语和关系,也要心中有数.. ~~~~~~~~~~~~~~~~~~~ 云计算在如今的IT界一直是一个最热门的话题,鉴 ...
- 字符串相似度算法(编辑距离算法 Levenshtein Distance)
在搞验证码识别的时候需要比较字符代码的相似度用到“编辑距离算法”,关于原理和C#实现做个记录.据百度百科介绍:编辑距离,又称Levenshtein距离(也叫做Edit Distance),是指两个字串 ...
- ANDROID_MARS学习笔记_S01原始版_023_MP3PLAYER003_播放mp3
一.简介 1.在onListItemClick中实现点击条目时,跳转到PlayerActivity,mp3info通过Intent传给PlayerActivity 2.PlayerActivity通过 ...
- vi编辑器的三种模式
1.命令模式(command mode)—执行命令 在该模式中,可以输入命令来执行许多种功能.控制屏幕光标的移动,字符.字或行的删除,移动复制某区段及进入Insert mode下,或者到 last l ...
- cocos2d-x 2.2 开发手记2
终于搞定了 吧后面没写的补上 装完那一堆更新,再来运行原生的项目,嗯,看见 模拟器啦 oh,yeah~~ 额,开心早了,由于我的机器实在有点老了 内存只有可怜的 2GB 这在官方里面写的是不能运行 ...