现在的位置: 首页 > 综合 > 正文

模板之泛化仿函数(一)

2018年03月30日 ⁄ 综合 ⁄ 共 5802字 ⁄ 字号 评论关闭

1 泛化仿函数的要求

参数个数应该是任意的,参数的型别也应该是任意的。

// 我们的Functor 应该是这样的,Functor 只是一个 wrapper(外覆类) 
template <typename ResultType, typename TList>
class Functor
{
public:
   ResultType operator()(); // 转发函数
   ResultType operator(Parm1 p1);
   ResultType operator(Parm1 p1, Parm2 p2);
   .....
};
struct T1
{
     double operator()(int, double)
     {
     // ....
     }
};
int foo()
{
     //...
}
int main()
{      
       Functor<double, TYPELIST_2(int, double)> myFunctor1(T1);
       myFunctor(4,4.5);
       // int foo(); 没有参数,返回值为 int
       Functor<int, NullType> myFunctor2(&foo);
       myFunctor2();
}

2 被 Functor 包覆的多态类 functorImpl 

template <typename R, class TList> 
class FunctorImpl
{

};

template <typename R>
class FunctorImpl < R, NullType >
{
public:
	virtual R operator()() = 0;
	virtual FunctorImpl* Clone() const = 0; // 产生FunctorImpl 对象的一份多态拷贝
	virtual ~FunctorImpl() {}               // 虚析构很重要
};

template <typename R, typename P1>
class FunctorImpl < R, TYPELIST_1(P1) >
{
public:
	virtual R operator() (P1) = 0;
	virtual FunctorImpl* Clone() const = 0;
	virtual ~FunctorImpl() {}
};

template <typename R, typename P1, typename P2>
class FunctorImpl < R, TYPELIST_2(P1, P2) >
{
public:
	virtual R operator() (P1, P2) = 0;
	virtual FunctorImpl* Clone() const = 0;
	virtual ~FunctorImpl() {}
};
// 带有 4、5、...更多参数的 FunctorImpl 

3 Functor 遵循典型的 handle-body 实现手法

template <typename R, class TList>
class Functor
{
private:
	typedef FunctorImpl<R, TList> Impl;
	std::auto_ptr<Impl> spImpl_; // 自动清除资源

public:
        // Functor 具备 value 语义
	Functor() : spImpl_(0) // default constructor 
	{}
	Functor(const Functor& rhs) : spImpl_(rhs.spImpl_.get()->Clone())  // copy constructor
	{}
	Functor& operator= (const Functor& rhs) // assignment operator
	{
		Functor copy(rhs);
		// swap auto_ptr by hand
		Impl *p = spImpl_.release();
		spImpl_.reset(copy.spImpl_.release());
		copy.spImpl_.reset(p);
		return *this;
	}
	explicit Functor(std::auto_ptr<Impl> spImpl) : spImpl_(spImpl) 
	{}

public:
        // 使用 TypeAtNonStrict 模板取得 typelist 中某个位置上的型别,ParmN 是typelist的第N个型别,如果 typelist 元素个数少于 N,获得结果将是 NullType
	typedef TList ParmList;
	typedef R ResultType;
	typedef typename TypeAtNonStrict<TList, 0>::Result Parm1;
	typedef typename TypeAtNonStrict<TList, 1>::Result Parm2;

	R operator()()
	{
		return (*spImpl_)();
	}
	R operator()(Parm1 p1)
	{
		return (*spImpl_)(p1);
	}
	R operator()(Parm1 p1, Parm2 p2)
	{
		return (*spImpl_)(p1, p2);
	}
        .....
};

4 处理仿函数

任何 class 实体只要定义有 operator(),都是仿函数。 Functor 满足这一定义,所以 Functor 是仿函数。因此“以仿函数 Fun之对象为参数”的 Functor 构造函数,是个“被Fun参数化”的templated 构造函数

template <typename R, class TList>
class Functor
{
     // ... as above
public:
      template <class Fun>
      Functor(const Fun& fun);
};
template <typename R, class TList>
template <typename Fun>  // 注:C++ 将这类代码称为“位于 class 本体之外的 member template 定义式”
Functor<R, TList>::Functor(const Fun& fun)
	: spImpl_(new FunctorHandler<Functor, Fun>(fun))
{


}

为了实现这个构造函数,我们需要一个从 FunctorImpl<R, TList>派生而来的class template FunctorHandler ,其中保存了一个型别为 Fun 的对象,并将 operator() 转发给该对象。

// FunctorHandler
template <class ParentFunctor, typename Fun>
class FunctorHandler
	: public FunctorImpl < typename ParentFunctor::ResultType,
	typename ParentFunctor::ParmList >
{
public:
	FunctorHandler(const Fun& fun) : fun_(fun) {}
	FunctorHandler* Clone() const
	{
		return new FunctorHandler(*this);
	}
public:
	typedef typename ParentFunctor::ResultType ResultType;
	ResultType operator()()
	{
		return fun_();
	}
	ResultType operator()(typename ParentFunctor::Parm1 p1)
	{
		return fun_(p1);
	}
	ResultType operator()(typename ParentFunctor::Parm1 p1,
		typename ParentFunctor::Parm2 p2)
	{
		return fun_(p1, p2);
	}

private:
	Fun fun_;
};
struct TestFunctor
{
	void operator()(int i, double d)
	{
		cout << "TestFunctor::operator()(" << i
			<< "," << d << ") called." << endl;
	}
};
void Test()
{
        cout << "Test" << endl;
}

int main()
{
	TestFunctor f;
	Functor<void, TYPELIST_2(int, double)> cmd(f);
	cmd(4, 4.5);
	Functor<void, NullType> cc(&Test); // 这里必须传函数指针而不是函数名
	cc();
}

5 参数和返回型别的转化

const char* TestFunc(double, double)
{
	static const char buffer [] = "Hello, world!";
	return buffer;
}

int main()
{
	Functor<string, TYPELIST_2(int, int)> cmd3(&TestFunc); // 隐式转换:参数 int -> double 
	cout << cmd3(10, 10).substr(7) << endl; // 返回值 const char* -> std::string

	return 0;
}

6 处理 pointer to member function

// member function 
template <class ParentFunctor, typename PointerToObj,
typename PointerToMemFn>
class MemFunHandler
	: public FunctorImpl < typename ParentFunctor::ResultType,
		typename ParentFunctor::ParmList >
{
public:
	typedef typename ParentFunctor::ResultType ResultType;
	MemFunHandler(const PointerToObj& pObj, const PointerToMemFn& pMemFn)
		: pObj_(pObj), pMemFn_(pMemFn)
	{}
	MemFunHandler* Clone() const
	{
		return new MemFunHandler(*this);
	}

	ResultType operator()()
	{
		return ((*pObj_).*pMemFn_)();
	}
	ResultType operator()(typename ParentFunctor::Parm1 p1)
	{
		return ((*pObj_).*pMemFn_)(p1);
	}
	ResultType operator()(typename ParentFunctor::Parm1 p1, 
			typename ParentFunctor::Parm2 p2)
	{
		return ((*pObj_).*pMemFn_)(p1, p2);
	}
private:
	PointerToObj pObj_;
	PointerToMemFn pMemFn_;
};
template <typename R, class TList>
class Functor
{
     // ... as above
public:
     	template <class PointerToObj, class PointerToMemFn>
	Functor(const PointerToObj& pObj, const PointerToMemFn& pMemFn);;
};

template <typename R, class TList>
template <typename PointerToObj, typename PointerToMemFn>
Functor<R, TList>::Functor(const PointerToObj& pObj, const PointerToMemFn& pMemFn)
	: spImpl_(new MemFunHandler<Functor, PointerToObj, PointerToMemFn>(pObj, pMemFn))
{


}
class Parrot
{
public:
	void Eat()
	{
		cout << "Tsk, knick, tsk..." << endl;
	}


	void Speak()
	{
		cout << "On Captain, My Captain" << endl;
	}
};
int main()
{
	// member function
	Functor<void, NullType > cmd1(&geronimo, &Parrot::Eat);
	Functor<void, NullType> cmd2(&geronimo, &Parrot::Speak);
	cmd1();
	cmd2();


	return 0;
}

7 重载函数传给 Functor 的歧义错误

void TestFunction(int i, double d)
{
	cout << "TestFunction: " << i
		<< "," << d << ") called." << endl;
}
void  TestFunction(int i)
{
	cout << "TestFunction: " << i << ") called." << endl; 
}
int main()
{
	// overload functions
	
	Functor<void, TYPELIST_2(int, double)> cmd1(&TestFunction); // error, 无法确定该使用哪一个 TestFunction 版本
		cmd1(5, 5.5);

	return 0;
}

如果你重载 TestFunction,就得想办法消除歧义性。原因是如果 TestFunction 被重载,其名称(符号)所代表的型别就不再有明确定义。

如果出现重载,两种方法可以识别其中某个函数:一使用赋值(assignment),二使用转型(cast)

int main()
{ 
	typedef void(*TpFun)(int, double);
	// method 1: use an assignment
	//TpFun pF = &TestFunction;
	TpFun pF = TestFunction; // the same with above
	Functor<void, TYPELIST_2(int, double)> cmd2(pF);
	cmd2(4, 4.5);
	// method 2: use a cast
	Functor<void, TYPELIST_2(int, double)> cmd3(static_cast<TpFun>(TestFunction));
	cmd3(5, 5.5);

	return 0;
}

赋值(assignment)和静态转型(static cast)都可以让编译器知道,你感兴趣的实际上是”参数为 int 和 double,返回类型为 void“的那个 TestFunction 函数。

抱歉!评论已关闭.