boost::function用法详解

今天学习muduo网络库源码的时候看到了boost::function,写篇笔记记录下。

书上是这样描述的:function是一个函数对象的“容器”,概念上像是C/C++中函数指针类型的泛华,是一种“智能函数指针”。它以对象的形式封装了原始的函数指针或函数对象,能够容纳任意符合函数签名的可调用对象。因此,它可以被用于回调机制,暂时保管函数或函数对象,在之后需要的时机在调用,使回调机制拥有更多弹性。
 

理解被存函数的最佳方法是把它想象为一个普通的函数对象(也可以想成一个模板类,使用的时候指定函数原型),该函数对象用于封装另一个函数(或函数对象)。这个被存的函数的最大用途是它可以被多次调用,而无须在创建 function 时立即使用。在声明 functions 时,声明中最重要的部分是函数的签名。这部分即是告诉 function 它将保存的函数或函数对象的签名和返回类型。这里有一个完整的程序,程序声明了一个 boost::function ,它可以保存返回 bool (或某个可以隐式转换为 bool 的类型)并接受两个参数的类函数实体,第一个参数可以转换为 int, 第二个参数可以转换为 double.

#include <iostream>
#include "boost/function.hpp"

bool some_func(int i,double d) {
  return i>d;
}

int main() {
  boost::function<bool (int,double)> f;    //bool指定返回类型,(xx,xx)指定参数类型
  f=&some_func;
  f(10,1.1);
}

当 function f 首次创建时,它不保存任何函数。它是空的,可以在一个布尔上下文中进行测试。如果你试图调用一个没有保存任何函数或函数对象的 function ,它将抛出一个类型 bad_function_call 的异常。为了避免这个问题,我们用普通的赋值语法把一个指向 some_func 的指针赋值给 f 。这导致 f 保存了到 some_func 的指针。最后,我们用参数10 (一个 int) 和 1.1 (一个 double)来调用 f (用函数调用操作符)。要调用一个 function, 你必须提供被存函数或函数对象所期望的准确数量的参数。
 

在function中可以使用ref、cref库来降低function参数的拷贝工作。function不要求ref库提供operator(),因为它能够自动识别包装类referrence_wrapper<T>,并调用get()方法获得被包装的对象,见下面代码片段。

将function用于回调,可以说是一个强大的功能之处。另外由于bind函数存在,甚至在我们使用回调函数时把不符合function要求的函数签名的函数通过bind函数来进行转换(主要是参数个数不一致的情况),而不需要改动回调接口。学习代码如下:
看代码之前可以先看下这篇介绍boost::bind()的博客:

boost::bind()详解

#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
using namespace boost;

int f(int a, int b)
{
	return a + b;
}

struct demo_class
{
	int add(int a,int b)
	{
		return a + b;
	}

	int operator()(int x)const
	{
		return x * x;
	}
private:
	typedef function<void(int)> func_t;//function类型定义
	func_t func;

	int n;//内部成员变量
public:
	demo_class(){};
	demo_class(int i):n(i){};

	template<typename CallBack>
	void accept(CallBack f)
	{
		func = f;
	}

	void run()
	{
		func(n);
	}
};

void call_back_func(int i)
{
	std::cout<<"call back func:";
	std::cout<<i * 2<<std::endl;
}

int main()
{
	function<int(int,int)> func;//无参构造function对象
	assert(!func);            //此时不持有任何对象

	func = f;    //func存储了f对象
	if (func)    //可以转换为bool值
	{
		std::cout<<func(10,20)<<std::endl;//调用function的operator()函数,并通过其将参数传给其持有的对象f
	}

	func = 0;    //将function对象清空,相当于clear函数
	assert(func.empty());    //使用empty()函数判断是否为空

	function<int(demo_class&,int,int)> func1;//用来存储成员函数时可以直接在function声明的函数签名中指定类的类型,然后用bind绑定成员函数,此处成员函数的返回类型没有指定啊?
	func1 = bind(&demo_class::add,_1,_2,_3);//需要绑定三个参数,一个是对象,另一个函数参数
	demo_class sc;
	std::cout<<func1(sc,20,20)<<std::endl;//调用类的成员函数sc::add(20,20)

    //下面的方法直观点,保持和普通函数调用方法一致
	function<int(int,int)> func2;//无参构造function对象
	func2 = bind(&demo_class::add,&sc,_1,_2);//比普通函数多了一个类对象地址
	std::cout<<func2(30,20)<<std::endl;//调用成员函数sc::add(30,20)

	function<int(int)> func3;
	func3 = cref(sc);//使用cref包装常对象的引用,参看demo_class::operator(int x)const
	std::cout<<func3(10)<<std::endl;  //func3(10) = sc::operator(10)

	//用于回调时
	demo_class dc(20);        //n = 20
	dc.accept(call_back_func);//接受回调函数
	dc.run();                //func(n): call_back_func(n)
	return 0;
}
扫描二维码关注公众号,回复: 3864780 查看本文章

猜你喜欢

转载自blog.csdn.net/amoscykl/article/details/83384906