软件架构设计之Utility模块——Functor

一:前言

         现在要实作一个泛化仿函数,泛化仿函数是将“请求(函数)封装起来”,存储与对象之中,该对象是具有“value语义”的,因此它支持拷贝,赋值和作为函数参数来传值(pass by value)。通过该对象可间接的处理它封装的请求,类似于boost 中的function功能。本实现采用的是《Modern C++ Design》中的方案。更详尽的说,它具有以下特点:

1.      可封装任何处理请求,它可接受函数指针,成员函数指针,仿函数,甚至其它泛化仿函数。

2.      具备型别安全性,不会将错误的型别匹配到错误的函数上。

3.      是一种带有“value语义的对象”。

首先介绍下C++中的可调用体:

1.      C风格的函数(C like function):  void fun();

2.      C风格的函数指针(C like pointto function): void (*pFun)();

3.      函数引用(reference to function),其行为本质上和const pointer to function类似。

4.      仿函数(functor),类中自定义了operator () 的对象。

5.      Operator.*和operator->*的施行结果

6.      构造函数

在上述的任一项,你可以在其右侧添加一对圆括号(),并在里头放入一组合适的参数。

先来讨论这样一个问题,既然想把函数请求封装到对象中,函数的参数如何确定?这里使用typelist(这是一个型别集,换句话说它包含型别列表)。这里就可以把typelist作为HTFunctor的一个模板参数,它包含所要封装函数的参数型别信息。下面就先介绍下typelist实作

二:HTTypeList

template <class T, class U>
struct HTTypeList
{
	typedef T Head;
	typedef U Tail;
};

这是typelist的基本实作(只需两个类型),现在问题是如何把n个类型连成链表。看下面这个例子就明白了

typedef HTTypeList<char, HTTypeList<int, int> >

(利用模板参数推导,而且是编译器自动产生,而不是运行期哦),这样两个以上的参数都解决了。

现在问题如何定义一个参数的typelist。方法是,第二个模板参数设为NullType(空类型),这样每个typelist都以NullType结尾,相当于C字符串的\0功能。看NullType的实作:

class HTNullType {};

接着就要生产typelist了(一个参数,两个参数,三个参数……)。这里用到宏,暂且定义4个typelist。

#define TYPELIST_1(T1) UTIL::HTTypeList<T1, UTIL::HTNullType>
#define TYPELIST_2(T1, T2) UTIL::HTTypeList<T1, TYPELIST_1(T2) >
#define TYPELIST_3(T1, T2, T3) UTIL::HTTypeList<T1, TYPELIST_2(T2, T3) >
#define TYPELIST_4(T1, T2, T3, T4) UTIL::HTTypeList<T1, TYPELIST_3(T2, T3, T4) >


另外要解决的问题是,函数参数该是值类型(内部内型)还是引用类型(对于对象)。选择合适的类型显然能提高程序速度,你肯定不想传递大对象参数时而要额外拷贝。接下来这个东西就要登场了——( HTTypeTraits

三:HTTypeTraits

可用于“编译期根据型别作判断”的泛型技术。大家也可参看boost中的type traits。

// 判断T及U是否标示同一个类型
template <typename T, typename U>
struct HTIsSameType
{
private:
	template<typename>
	struct In 
	{ enum { value = false }; };

	template<>
	struct In<T>
	{ enum { value = true };  };

public:
	enum { value = In<U>::value };
};
// 依flag选择两个类型中的一个,true为T,false为U
template <bool flag, typename T, typename U>
struct HTSelect
{
private:
	template<bool>
	struct In 
	{ typedef T Result; };

	template<>
	struct In<false>
	{ typedef U Result; };

public:
	typedef typename In<flag>::Result Result;
};
// 编译期bool型
typedef char HTYes;
struct HTNo { char padding[8]; };

// 型别映射为型别,用于模板函数的偏特化,C++标准模板函数不能偏特化
template <typename T>
struct HTType2Type { typedef T Type; };

// 判断T是否为类
template <typename T>
struct HTIsClass
{
	// U为类的话,会具现化此重载函数,因为参数为函数指针,即指向成员的函数指针
	template <typename U> static HTYes IsClassTest(void(U::*)(void));
	// U为非类,会具现化此重载函数
	// C++标准:只有当其它所有的重载版本都不能匹配时,具有任意参数列表的重载版本才会被匹配
	template <typename U> static HTNo IsClassTest(...);

	// 对于sizeof,表达式不会被真正求值,编译器只推导出表达式的返回结果的型别,因此只需函数的声明即可
	static const bool value = sizeof(IsClassTest<T>(0)) = sizeof(HTYes);
};

// 判断T是否为引用类型
template <typename T>
struct HTIsReference
{
	template <typename U> static HTYes IsReference(HTType2Type<U&>);
	template <typename U> static HTNo IsReference(...);

	static const bool value= sizeof(IsReference(HTType2Type<T>())) == sizeof(HTYes);
};

template <typename T>
class HTTypeTraits
{

public:
	enum { 
		isVoid = 
		HTIsSameType<T, void>::value          ||
		HTIsSameType<T, const void>::value    ||
		HTIsSameType<T, volatile void>::value ||
		HTIsSameType<T, const volatile void>::value
	};

	enum { isReference = HTIsReference<T>::value };

private:
	template<bool IsRef>
	struct AdjReference
	{
		template<typename U>
		struct In { typedef U const & Result; };
	};

	template<>
	struct AdjReference<true>
	{
		template<typename U>
		struct In { typedef U Result; };
	};

	typedef typename AdjReference<isReference || isVoid>::
		template In<T>::Result AdjType;

	// 正确的选择函数参数的类型
	// 对于精巧型(有构造函数和析构函数额外调用)采用引用传参数,对于纯量型(数值型别,枚举型别,指针,指向成员的指针)采用直接传值
	typedef typename HTSelect<HTIsClass<T>::value, AdjType, T>::Result ParmType;
};

四:HTFunctor

HTTypeList及HTTypeTraits提供我们强大的功能。这让我们实作HTFunctor更加的方便。下面直接看代码。

// Functor对象明显是个小对象,这里采用小对象分配器
// 使用了Command模式及IMPL模式
template <typename R>
struct HTFunctorImplBase : public HTSmallObject<>
{
	typedef R	ResultType;
	typedef HTEmptyType	Parm1;
	typedef HTEmptyType Parm2;
};

template <typename R, class TList, class ObjClass>
struct HTFunctorImpl;

// 无参数版本
template <typename R, class ObjClass>
struct HTFunctorImpl<R, HTNullType, ObjClass> : public HTFunctorImplBase<R>
{
	typedef R		ResultType;

	virtual ResultType operator()(ObjClass* pObj) = 0;
	virtual HTFunctorImpl* Clone() const = 0;
	virtual ~HTFunctorImpl() {}
};

// 一个参数版本
template <typename R, typename P1, class ObjClass>
struct HTFunctorImpl<R, TYPELIST_1(P1), ObjClass> : public HTFunctorImplBase<R>
{
	typedef R		ResultType;
	typedef typename HTTypeTraits<P1>::ParmType	Parm1;

	virtual ResultType operator()(Parm1, ObjClass* pObj) = 0;
	virtual HTFunctorImpl* Clone() const = 0;
	virtual ~HTFunctorImpl() {}
};

// 两个参数版本
template <typename R, typename P1, typename P2, class ObjClass>
struct HTFunctorImpl<R, TYPELIST_2(P1, P2), ObjClass> : public HTFunctorImplBase<R>
{
	typedef R		ResultType;
	typedef typename HTTypeTraits<P1>::ParmType	Parm1;
	typedef typename HTTypeTraits<P2>::ParmType Parm2;

	virtual ResultType operator()(Parm1, Parm2, ObjClass* pObj) = 0;
	virtual HTFunctorImpl* Clone() const = 0;
	virtual ~HTFunctorImpl() {}
};

// 可调用体(即封装的处理函数)为仿函数
template <class ParentFunctor, typename Fun, class ObjClass>
class HTFunctorHandler : 
	public HTFunctorImpl
				< 
				typename ParentFunctor::ResultType,
				typename ParentFunctor::ParmList,
				ObjClass
				>
{
	typedef typename ParentFunctor::Impl	Base;
public:
	typedef typename Base::ResultType ResultType;

	typedef typename Base::Parm1 Parm1;
	typedef typename Base::Parm1 Parm2;

	HTFunctorHandler(const Fun& fun) : m_fun(fun) {}
	HTFunctorHandler* Clone() const { return new HTFunctorHandler(*this); }

	ResultType operator()(ObjClass* pObj) 
	{ return m_fun(); }

	ResultType operator()(Parm1 p1, ObjClass* pObj)
	{ return m_fun(p1); }

	ResultType operator()(Parm1 p1, Parm2 p2, ObjClass* pObj)
	{ return m_fun(p1, p2); }

private:
	Fun m_fun;
};

// 可调用体(即封装的处理函数)为类成员函数,调用需传递对象指针
template <class ParentFunctor, typename Fun, class ObjClass>
class HTMemFunHandler : 
	public HTFunctorImpl
				< 
				typename ParentFunctor::ResultType,
				typename ParentFunctor::ParmList,
				ObjClass
				>
{
	typedef typename ParentFunctor::Impl	Base;
public:
	typedef typename Base::ResultType ResultType;

	typedef typename Base::Parm1 Parm1;
	typedef typename Base::Parm1 Parm2;

	HTMemFunHandler(const Fun& fun) : m_fun(fun) {}
	HTMemFunHandler* Clone() const { return new HTMemFunHandler(*this); }

	ResultType operator()(ObjClass* pObj) 
	{ return (pObj->*m_fun)(); }

	ResultType operator()(Parm1 p1, ObjClass* pObj) 
	{ return (pObj->*m_fun)(p1); }

	ResultType operator()(Parm1 p1, Parm2 p2, ObjClass* pObj)
	{ return (pObj->*m_fun)(p1, p2); }

private:
	Fun m_fun;
};

// HTFunctor实现体
template <typename R, class TList = YKNullType, class ObjClass = YKEmptyType>
class HTFunctor
{
	typedef HTFunctorImpl<R, TList, ObjClass> Impl;
public:
	typedef R		ResultType;
	typedef TList	ParmList;
	typedef typename Impl::Parm1 Parm1;
	typedef typename Impl::Parm2 Parm2;

	HTFunctor() : m_spImpl() {}
	HTFunctor(const HTFunctor& rhs) : m_spImpl(rhs.m_spImpl->Clone()) {}
	explicit HTFunctor(std::auto_ptr<Impl> spImpl) : m_spImpl(spImpl) {}

	HTFunctor& operator=(const HTFunctor& rhs)
	{
		HTFunctor copy(rhs);
		Impl* p = m_spImpl.release();
		m_spImpl.reset(copy.m_spImpl.release());
		copy.m_spImpl.reset(p);
		return *this;
	}

	template <typename Fun>
	HTFunctor(Fun fun)
		: m_spImpl(new 
		HTSelect<
			HTIsSameType<ObjClass, HTEmptyType>::value, 
			HTFunctorHandler<HTFunctor, Fun, ObjClass>, 
			HTMemFunHandler<HTFunctor, Fun, ObjClass> >::Result(fun))
	{}

	ResultType operator()(ObjClass* pObj = HT_NULL) {
		return (*m_spImpl)(pObj);
	}

	ResultType operator()(Parm1 p1, ObjClass* pObj = HT_NULL) {
		return (*m_spImpl)(p1, pObj);
	}

	ResultType operator()(Parm1 p1, Parm2 p2, ObjClass* pObj = HT_NULL) {
		return (*m_spImpl)(p1, p2, pObj);
	}

private:
	std::auto_ptr<Impl> m_spImpl;
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值