首页 > 代码库 > C++模板 - traits & policy

C++模板 - traits & policy

traits和policy在泛型编程里面还是挺常见的。像stl的string实现里面就用到了traits,boost里面也很多地方用到traits。

traits和policy很多时候都会一起使用,让我们在泛型编程里面多了一些思路。

traits:中文解释为特征,记得候捷在《stl源码剖析》那本书里面还叫做萃取什么的。当我们想从一个类型身上获取他的一个附加特性的时候,往往可以考虑traits。比方说有一个类型T, 对他进行一些操作,然后要返回一个类型,那么可以理解为一个返回类型是跟T相关的。还有比如给定一个迭代器,想从迭代器上获取相关的容器类型什么。这个都是type traits的典型应用,至于value traits,很多时候是在一个traits里面给类型附加一个初始化值。经常可以看到一个tratis类里面有一个类型定义和一个相应的初始化(静态常量或者一个静态函数)。类似:

template<>
struct traits<int>
{
	typedef double AccuT;
	static AccuT Zero(){ return 0.0; };
};


policy:中文解释为策略。在泛型编程里面,如果某些行为代码可能会变化,那么往往可以使用policy。通过使用不同的policy可以改变一个模板函数的行为。比如下面的代码:

template<class T, class P>
typename traits<T>::AccuT accum(const T* ptr, int len)
{
	traits<T>::AccuT total = traits<T>::Zero();

	for (int i = 0; i < len; i++)
	{
		P::accumulate(total, *(ptr + i));
	}

	return total;
}

如果累加算法可能会变,那么我们就可以通过传入一个模板类,通过这个类的成员函数来实现不同的算法。

 

traits和policy拓展了我们的视野,让我们多了一些思路。但是也不要一味的滥用(就像设计模式一样,有些时候过度设计还不如没有设计)。

stl的accumulate函数就没有使用traits和policy。看下面的代码:

template<class _InIt,
	class _Ty> inline
	_Ty accumulate(_InIt _First, _InIt _Last, _Ty _Val)
	{	// return sum of _Val and all in [_First, _Last)
	_DEBUG_RANGE(_First, _Last);
	return (_Accumulate(_Unchecked(_First), _Unchecked(_Last), _Val));
	}

 

template<class _InIt,
	class _Ty,
	class _Fn2> inline
	_Ty accumulate(_InIt _First, _InIt _Last, _Ty _Val, _Fn2 _Func)
	{	// return sum of _Val and all in [_First, _Last), using _Func
	_DEBUG_RANGE(_First, _Last);
	_DEBUG_POINTER(_Func);
	return (_Accumulate(_Unchecked(_First), _Unchecked(_Last), _Val, _Func));
	}


std::accumulate()的返回值类型其实是通过一个模板参数传进去的_Ty _Val。行为函数也是通过一个模板参数穿进去的_Fn2 _Func。

个人感觉每种方案都有自己的优缺点,还是那句话,在合适的场合使用合适的解决方案。方案本身没有绝对的好和不好,只有合适的方案没有最好的方案(只有最强的玩家没有最强的职业)

traits的原作者Nathan有句话:traits是一种替代模板参数的方案。但是他并没有说模板参数不好,或者traits比模板参数好多少。

C++模板 - traits & policy