function 源码分析1--boost function缩水版本实现

我们要实现一个和function接口一样的类

首先function可以是void(int),void(int,int),void(int,int,int),最开始不明白如何实现,其实很简单,class特化而已。

	template<typename Signature> class function;
	template<typename R>
	class function<R()>
	{
		//...
	};
	template<typename R,typename T1>
	class function<R(T1)>
	{
		//...
	};
	template<typename R, typename T1,typename T2>
	class function<R(T1,T2)>
	{
		//...
	};
	//...
这样根据不同的signature,就可以得到不同的function。

其次,我们的目标是能够支持函数指针和仿函数(成员函数可以通过仿函数来完成,下篇分析源码时介绍);

1.函数指针,函数指针只要能够保存函数地址,调用时使用指针来完成。

2.仿函数,这个只能利用拷贝构造new一个拷贝,将new出来的仿函数的指针保存下来,function析构时再delete。

要支持不同的类型,我第一时间想到的是接口,然后由子类实现,这也是我最开始对委托的理解,这样的做法效率比较低。从上面的分析可知,不管哪种类型,我们都需要保存指针,但是调用的时候,调用方法不同。而function<int(int)>,function<void(int,int)>类型的函数指针类型是不同的,但是存储到内存中都是一个指针,所以boot function定义了一个类型,

function_buffer,用来存储指针

union function_buffer
{
	// For pointers to function objects
	mutable void* obj_ptr;
	// For function pointers of all kinds
	mutable void(*func_ptr)();
};
所有的function都使用上述对象来存储。问题是如何调用,这可以通过函数指针类完成invoke,函数指针和仿函数调用不同的invoke指针来完成。

以function1为例,我们目前基本具备了以下代码:

#include <stdexcept>
template<typename Signature> class function;
/// \brief 当函数指针为空时抛出异常
class bad_function_call : public std::runtime_error
{
public:
	bad_function_call() : std::runtime_error("call to empty boost::function") {}
};

template<typename R,typename T0>
class function<R(T0)>
{
public:
	function()
	{
		invoker = nullptr;
	}
	typedef R(*invoker_type)(function_buffer&, T0);///<函数调用指针
	R operator()(T0 a0) const
	{
		if (this->empty())
			throw new bad_function_call();
		return invoker(this->functor, a0);
	}
	bool empty() const 
	{ 
		return !invoker;
	}
private:
	invoker_type invoker;
	function_buffer functor;
};
有一点有问题,我们没有函数指针和仿函数对象的构造函数,同时,我们也没有对仿函数的指针delete。而且function需要拷贝构造,移动构造,这样我们使用一个新的函数指针,manager来操作,如下,通过传入不同的tag,我们就可以实现不同的操作。

enum functor_manager_operation_type {
	clone_functor_tag,
	move_functor_tag,
	destroy_functor_tag
};
struct vtable_base
{
	void(*manager)(const function_buffer& in_buffer,
		function_buffer& out_buffer,
		functor_manager_operation_type op);
};
我们的function变为

template<typename R,typename T0>
class function<R(T0)>
{
public:
	function()
	{
		invoker = nullptr;
	}
	~function()
	{
		vtable->manager(f.functor, this->functor, destroy_functor_tag);
	}
	typedef R(*invoker_type)(function_buffer&, T0);
	R operator()(T0 a0) const
	{
		if (this->empty())
			throw new bad_function_call();
		return invoker(this->functor, a0);
	}
	bool empty() const 
	{ 
		return !invoker;
	}
	function(const function& f)
	{
		assign_to(f);
	}
	function(function&& f)
	{
		vtable->manager(f.functor, this->functor,move_functor_tag);
	}
	function& operator=(const function& f)
	{
		assign_to(f);
		return *this;
	}
	function& operator=(function&& f)
	{
		if (&f == this)
			return;
		vtable->manager(f.functor, this->functor, move_functor_tag);
	}
private:
	vtable_base* vtable;
	invoker_type invoker;
	function_buffer functor;
	void assign_to(const function& f)
	{
		vtable->manager(f.functor, this->functor, clone_functor_tag);
	}
};
在加入构造函数之前,我们先实现manage的不同版本

template<typename Functor>
struct functor_manager_common
{
	typedef Functor functor_type;
	//函数指针
	static inline void manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer,
			functor_manager_operation_type op)
	{
		if (op == clone_functor_tag)
			out_buffer.func_ptr = in_buffer.func_ptr;
		else if (op == move_functor_tag) {
			out_buffer.func_ptr = in_buffer.func_ptr;
			in_buffer.func_ptr = 0;
		}
		else  /* op == destroy_functor_tag */{
			out_buffer.func_ptr = 0;
		}
	}
	//仿函数指针
	static inline void manager(const function_buffer& in_buffer, function_buffer& out_buffer,
			functor_manager_operation_type op)
	{
		if (op == clone_functor_tag) {
			const functor_type* f =static_cast<const functor_type*>(in_buffer.obj_ptr);
			functor_type* new_f = new functor_type(*f);
			out_buffer.obj_ptr = new_f;
		}
		else if (op == move_functor_tag) {
			out_buffer.obj_ptr = in_buffer.obj_ptr;
			in_buffer.obj_ptr = 0;
		}
		else /*op == destroy_functor_tag*/{
			/* Cast from the void pointer to the functor pointer type */
			functor_type* f =static_cast<functor_type*>(out_buffer.obj_ptr);
			delete f;
			out_buffer.obj_ptr = 0;
		}
	}
};
以上内容不难读懂,不多说了,再就是invoke的不同版本了,

template<typename FunctionPtr,typename R,typename T0>
struct function_invoker1
{
	static R invoke(function_buffer& function_ptr,
		T0 a0)
	{
		FunctionPtr f = reinterpret_cast<FunctionPtr>(function_ptr.func_ptr);
		return f(a0);
	}
};
template<typename FunctionObj,typename R,typename T0>
struct function_obj_invoker1
{
	static R invoke(function_buffer& function_obj_ptr,T0 a0)
	{
		FunctionObj* f= reinterpret_cast<FunctionObj*>(function_obj_ptr.obj_ptr);
		return (*f)(a0);
	}
};
有了上面所有实现,我们就可以开始实现function的构造函数,我们希望根据不同的输入,去调用不同的invoke,manage,所以我们需要区分构造参数的不同,

这里需要使用元编程的一些轮子,如下

struct function_ptr_tag {};
struct function_obj_tag {};

template<typename F>
class get_function_tag
{
	typedef typename boost::mpl::if_c<(boost::is_pointer<F>::value),
		function_ptr_tag,
		function_obj_tag>::type ptr_or_obj_tag;
public:
	typedef ptr_or_obj_tag type;
};
这里if_c通过判断F是不是指针来决定function_tag的type类型是function_ptr_tag或者function_obj_tag,有了上面的努力,下面的代码就很简单了

	template<typename Functor>
	function(Functor const & f):
	vtable(nullptr),
	invoker(nullptr)
	{
		typedef typename get_function_tag<Functor>::type tag;
		this->assign_to(f, tag());
	}
这里的assign_to根据tag的不同,初始化不同参数,首先是函数指针

	template<typename FunctionPtr>
	void assign_to(FunctionPtr f, function_ptr_tag)
	{
		static vtable_base stored_vtable = { &functor_manager_common<FunctionPtr>::manage_ptr };
		Clear();
		if (f) {
			functor.func_ptr = reinterpret_cast<void(*)()>(f);
		}
		vtable = &stored_vtable;
		invoker = &function_invoker1<FunctionPtr, R, T0>::invoke;
	}

接着仿函数

	template<typename FunctionObj>
	void assign_to(FunctionObj f, function_obj_tag)
	{
		static vtable_base stored_vtable = {&functor_manager_common<FunctionObj>::manager};
		functor.obj_ptr = new FunctionObj(f);
		vtable = &stored_vtable;
		invoker=&function_obj_invoker1<FunctionObj, R, T0>::invoke;
	}

至此,我们的一元function的代码编码完毕,完整代码如下,我加了一些测试代码:

#include <stdexcept>
#include <boost\mpl\if.hpp>
#include <boost\type_traits\is_pointer.hpp>
#include <assert.h>
union function_buffer
{
	// For pointers to function objects
	mutable void* obj_ptr;
	// For function pointers of all kinds
	mutable void(*func_ptr)();
};

template<typename Signature> class function;

class bad_function_call : public std::runtime_error
{
public:
	bad_function_call() : std::runtime_error("call to empty boost::function") {}
};
enum functor_manager_operation_type {
	clone_functor_tag,
	move_functor_tag,
	destroy_functor_tag
};
struct vtable_base
{
	void(*manager)(const function_buffer& in_buffer,
		function_buffer& out_buffer,
		functor_manager_operation_type op);
};

template<typename Functor>
struct functor_manager_common
{
	typedef Functor functor_type;
	//函数指针
	static inline void manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer,
		functor_manager_operation_type op)
	{
		if (op == clone_functor_tag)
			out_buffer.func_ptr = in_buffer.func_ptr;
		else if (op == move_functor_tag) {
			out_buffer.func_ptr = in_buffer.func_ptr;
			in_buffer.func_ptr = 0;
		}
		else  /* op == destroy_functor_tag */ {
			out_buffer.func_ptr = 0;
		}
	}
	//仿函数指针
	static inline void manager(const function_buffer& in_buffer, function_buffer& out_buffer,
		functor_manager_operation_type op)
	{
		if (op == clone_functor_tag) {
			const functor_type* f = static_cast<const functor_type*>(in_buffer.obj_ptr);
			functor_type* new_f = new functor_type(*f);
			out_buffer.obj_ptr = new_f;
		}
		else if (op == move_functor_tag) {
			out_buffer.obj_ptr = in_buffer.obj_ptr;
			in_buffer.obj_ptr = 0;
		}
		else /*op == destroy_functor_tag*/ {
			/* Cast from the void pointer to the functor pointer type */
			functor_type* f = static_cast<functor_type*>(out_buffer.obj_ptr);
			delete f;
			out_buffer.obj_ptr = 0;
		}
	}
};
template<typename FunctionPtr,typename R,typename T0>
struct function_invoker1
{
	static R invoke(function_buffer& function_ptr,T0 a0)
	{
		FunctionPtr f = reinterpret_cast<FunctionPtr>(function_ptr.func_ptr);
		return f(a0);
	}
};
template<typename FunctionObj,typename R,typename T0>
struct function_obj_invoker1
{
	static R invoke(function_buffer& function_obj_ptr,T0 a0)
	{
		FunctionObj* f= reinterpret_cast<FunctionObj*>(function_obj_ptr.obj_ptr);
		return (*f)(a0);
	}
};

struct function_ptr_tag {};
struct function_obj_tag {};

template<typename F>
class get_function_tag
{
	typedef typename boost::mpl::if_c<(boost::is_pointer<F>::value),
		function_ptr_tag,
		function_obj_tag>::type ptr_or_obj_tag;
public:
	typedef ptr_or_obj_tag type;
};
template<typename R, typename T0>
class function<R(T0)>
{
	typedef R(*invoker_type)(function_buffer&, T0);
public:
	function()
	{
		invoker = nullptr;
	}
	template<typename Functor>
	function(Functor const & f):
	vtable(nullptr),
	invoker(nullptr)
	{
		typedef typename get_function_tag<Functor>::type tag;
		this->assign_to(f, tag());
	}
	~function()
	{
		Clear();
	}
	R operator()(T0 a0)
	{
		if (this->empty())
			throw new bad_function_call();
		return invoker(this->functor, a0);
	}
	bool empty() const
	{
		return !vtable;
	}
	function(const function& f)
	{
		assign_to(f);
	}
	function(function&& f)
	{
		vtable->manager(f.functor, this->functor, move_functor_tag);
	}
	function& operator=(const function& f)
	{
		assign_to(f);
		return *this;
	}
	function& operator=(function&& f)
	{
		if (&f == this)
			return;
		vtable->manager(f.functor, this->functor, move_functor_tag);
	}
private:
	vtable_base* vtable;
	invoker_type invoker;
	function_buffer functor;
	void Clear()
	{
		if (vtable) {
			vtable->manager(functor, functor, destroy_functor_tag);
			vtable = nullptr;
		}
	}
	void assign_to(const function& f)
	{
		vtable->manager(f.functor, this->functor, clone_functor_tag);
	}
	template<typename FunctionPtr>
	void assign_to(FunctionPtr f, function_ptr_tag)
	{
		static vtable_base stored_vtable = { &functor_manager_common<FunctionPtr>::manage_ptr };
		Clear();
		if (f) {
			functor.func_ptr = reinterpret_cast<void(*)()>(f);
		}
		vtable = &stored_vtable;
		invoker = &function_invoker1<FunctionPtr, R, T0>::invoke;
	}
	template<typename FunctionObj>
	void assign_to(FunctionObj f, function_obj_tag)
	{
		static vtable_base stored_vtable = {&functor_manager_common<FunctionObj>::manager};
		functor.obj_ptr = new FunctionObj(f);
		vtable = &stored_vtable;
		invoker=&function_obj_invoker1<FunctionObj, R, T0>::invoke;
	}
};
class Test
{
public:
	int operator()(int a)
	{
		return a;
	}
	static int static_fun(int a)
	{
		return a;
	}
};
int main()
{
	Test f_Test;
	function<int(int)> f_fun1(f_Test);
	function<int(int)> f_fun2(&Test::static_fun);
	assert(1 == f_fun1(1));
	assert(2 == f_fun2(2));
    return 0;
}
我们把T0换成T0,T1,这样我们就可以实现二参函数,以此类推,但是复制代码是原罪,这里大概说下boot的实现方法,

我们一般写头文件时,要求要么加#pragma once,要么使用宏隔开,防止头文件重复包含。此刻,我们需要利用头文件的重复包含,定义function_template.hpp文件,但是不使用宏保护,然后在function1中定义下列宏

#define BOOST_FUNCTION_FUNCTION_INVOKER ...
#define BOOST_FUNCTION_FUNCTION_OBJ_INVOKER ...
#define BOOST_FUNCTION_FUNCTION_REF_INVOKER ...
...
#include <function_template.hpp>
#undef BOOST_FUNCTION_FUNCTION_INVOKER
#undef BOOST_FUNCTION_FUNCTION_OBJ_INVOKER
#undef BOOST_FUNCTION_FUNCTION_REF_INVOKER
...

这样就可以利用同一份代码实现不同参数的function。当然,boot库使用了宏递归来实现的上述参数定义,就不再赘述,这个不是function的重点。

以上基本实现了一个function的缩水版本,理解了上面简单的代码,看boost源码就容易多了。
























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值