成员模版和模版的模板参数
之前我们为了实现一个累积的policy,我们选择把SumPolicy和MutPolicy实现为具有成员模版的普通类,这里,还存在另一种实现方法,即使用类模板来实现这个policy class接口:
#ifndef SUMPOLICY_H #define SUMPOLICY_H template<typename T1,typename T2> class SumPolicy { public: static void accumulate(T1& total,T2 const & value) { total += value; } }; #endif
我们对累积求和类Accum的接口进行修改,从而使用一个模板的模板参数,代码如下:
#ifndef ACCUM_H #define ACCUM_H #include "accumtraits4.h" #include "sumpolicy2.h" template<typename T, template<typename,typename> class Policy = SumPolicy, typename Traits = AccumulationTraits<T> > class Accum { public: typedef typename Traits::AccT AccT; static AccT accum(T const *beg,T const *end) { AccT total = Traits::zero(); while (beg != end) { Policy<AccT,T>::accumulate(total,*beg); ++beg; } return total; } };
实际上也可以对trait参数应用这种相同的转化。
通过模板的模板参数访问policy class的主要优点在于:借助于某个依赖于模板参数的类型,就很容易让policy class携带一些状态信息(也就是静态成员变量)。而在之前的解决方案中,却不得不把静态成员变量嵌入到成员类模板中。然而,这种模板的模板参数也存在一个缺点:policy类现在必须被写成模板,而且我们的接口中还定义了模板参数的确切个数。遗憾的是,这个定义会让我们无法在policy中添加额外的模板参数。例如:我们希望给SumPolicy添加一个Boolean型的非类型模板实参,从而可以选择是用+=运算符来进行求和,还是只用+运算符来进行求和。如果我们不使用模板的模板参数,我们只需这样改动SumPolicy模板即可:
#ifndef SUMPOLICY_H #define SUMPOLICY_H template<bool use_compound_op = true> class SumPolicy { public: template<typename T1, typename T2> static void accumulate(T1& total,T2 const & value) { total += value; } }; template<> class SumPolicy<false> { public: template<typename T1,typename T2> static void accumulate(T1& total,T2 const & value) { total = total + value; } }; #endif
然而,如果我们使用模板的模板参数来实现上面的Accum,那么将不能做这样的修改。
下面,我们运用普通的迭代器进行累积
#ifndef ACCUM_H #define ACCUM_H #include <iterator> #include "accumtraits4.h" template<typename Iter> inline typename std::iterator_traits<Iter>::value_type accum(Iter start,Iter end) { typedef typename std::iterator_traits<Iter>::value_type VT; VT total = VT(); while (start != end) { total += *start; ++start; } return total; } #endif
其中,iterator_traits是C++标准库提供的trait(可以看出,到处都是trait)。该结构封装了迭代器的所有相关属性。由于存在一个适合指针的局部特化,所以普通指针类型也能使用这些trait。下面的(不完整的)例子展示了:标准库如何实现和如何提供这些支持的:
namespace std{ template <typename T> struct iterator_traits<T*>{ typedef T value_type; typedef ptrdiff_t difference_type; typedef random_access_iterator_tag iterator_category; typedef T* pointer; typedef T& reference; }; }