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,那是一种可视化编程语言,所谓的可视化,就是运行结果能直接看得到的,非常直观,便于调试,适合刚刚接触编程的新人学习.当时学得懵懂,半知半解,就是感觉程序非常神奇,常常几句代码 ...
随机推荐
- 敏捷开发概述与路线(转自MBAlib)
敏捷开发的概述 简单的说,敏捷开发是一种以人为核心.迭代.循序渐进的开发方法.在敏捷开发中,软件项目的构建被切分成多个子项目,各个子项目的成果都经过测试,具备集成和可运行的特征.换言之,就是把一个大项 ...
- 利用 runtime,解决多次点击相同 button,导致重复跳转的问题-b
当app有点卡的时候,多次点击相同的button,经常出现,跳转了N次相同的界面(比如闲鱼) 解决办法 用运行时和分类,替换 UIControl 响应事件,根据响应的间隔时间来判断是否执行事件. 详细 ...
- 仿今日头条最强顶部导航指示器,支持6种模式-b
项目中经常会用到类似今日头条中顶部的导航指示器,我也经常用一个类似的库PagerSlidingTabStrip,但是有时并不能小伙伴们的所有需求,所以我在这个类的基础上就所有能用到的情况做了一个简单的 ...
- vs2013下使用Assist X的破解方法
Assist X的破解下载:http://pan.baidu.com/s/1kTnDH23 密码:j9jp 01.安装,点击VA_X_Setup2042.exe 安装 02.破解 找到这样的目录:C: ...
- delphi xe5 android listbox的 TMetropolisUIListBoxItem
listbox实现以下效果: \ 关键代码,采用数据集的方式 type PpatientData=^RpatientData; RpatientData= record patient_id:stri ...
- PHP漏洞全解(七)-Session劫持
本文主要介绍针对PHP网站Session劫持.session劫持是一种比较复杂的攻击方法.大部分互联网上的电脑多存在被攻击的危险.这是一种劫持tcp协议的方法,所以几乎所有的局域网,都存在被劫持可能. ...
- packinfo-java的作用
package-info.java 包的作用 1. 为标注在包上的Annotation提供便利 2. 声明包的私有类和常量 3. 提供包的整体注释说明 代码说明: package-info.jav ...
- 如何用CURL并解释JSON
CURL *curl; CURLcode res; struct curl_slist *headers=NULL; // init to NULL is important headers = cu ...
- protel dxp快捷键大全
enter——选取或启动 esc——放弃或取消f1——启动在线帮助窗口tab——启动浮动图件的属性窗口pgup——放大窗口显示比例pgdn——缩小窗口显示比例end——刷新屏幕del——删除点取的元件 ...
- 匿名函数和Lambda表达式
这个题目有点牵强,真不知道如何取一个比较中意的名称,写技术博客,我很少拘泥小节,但是注重细节,如果细节都出现问题了,那么这个博文也就失去了价值. 其实应该从委托说起,委托是C#中的一个重要的内容,记得 ...