首页 > 代码库 > C++必知必会(6)

C++必知必会(6)

条款55模板的模板参数

见一下stack适配器采用默认Deque的例子

template<typename T, class Cont =Deque<T>>

class Stack{

public:

       ~stack();

void push();

private:

       Conts_;

};

这里,Stack的用户现在必须提供一个模板实参,表示元素的类型,还可以提供一个表示容器的类型(默认为deque<T>),并且容器必须能够容纳该元素类型的对象。

如果Stack的用户乐于接受一个Deque实现或者不是特别关心其实现时,这回很有帮助:

Stack<int>aStack1;           //容器Deque<int>

Stack<double>aStack2;    //容器是Deuque<double>

然而,这种方式是以安全性为代价的,因为当其使用其他容器进行特化时,这种方式仍然需要协调元素和容器的类型,显然,这种协调的要求,就可能会带来不协调:

Stack<int,List<int>> aStack3;

Stack<int,List<unsigned>> aStack4;      //哎呀!错误!

解决办法:一个模板可以带有一个自身就是模板名字的参数。这种参数叫做:模板的模板参数。

Stack模板使用其类型名字参数来实例化其模板的模板参数,所得到的容器类型用于实现Stack:

       template<typenameT, template <typename> class Cont = Deque>

       classStack{

       //…

       private:

              Cont<T>s_;

};

这种方式可以使元素和容器类型之间的协调问题通过Stack自身的实现来解决,而不是特化Stack的各种代码中进行解决。

Stack<int,List> aStack1;   //OK,Cont是一个List

Stack<std::string> aStack;       //OK,使用默认参数值,Cont是一个Deque

条款56 policy

如果一个策略比其他策略更常用,通常可把它作为默认policy。

条款57模板实参推导

template<typename T>

T min(const T& a, const T& b)

{return a<b ?a:b; }

 

int a = min(12,13);     //T是int

double d = min(‘\b’, ‘\a’);  //T是char

char c = min(12.3, 4);       //错误!T不能既是double又是int

 

上面代码是错误的,原因在于编译器无法在默认两个的情况下推导出模板参数。在这种情况下,我们总是可以用显式的方式告诉编译器,模板实参究竟是什么:

d = min<double>(12.3, 4);              //OK,T是double

让编译器根据函数调用中的实参类型推导模板实参。这在情理中,这个过程称为实参推导。任何无法从实参推导出来的模板实参都必须显式予以提供。

函数模板实参推导机制可用来间接地特化类模板。考虑一个可用于从函数指针来生成函数对象的类模板:

template<typenameA1, typename A2, typename R>

class Pfun2 :public std::binary_function<A1,A2,R>{

public:

       explict Pfun2(R (*fp)(A1, A2)) :fp_(fp){}

       R operator()(A1 a1, A2 a2) const{ returnfp_(a1, 2);}

private:

       R (*fp_)(A1, A2);

};

直接实例化这个模板有点麻烦:

boolisGreater(int, int);

std::sort(b, e, Pfun2<int,int, bool>(isGreater));  //痛苦!

对于此种情况,通常可以提供一个辅助函数,该函数唯一用途在于推导模板实参,为的是可以像施魔法一般去特化一个类模板:

template<typenameR, typename A1, typename A2>

inline Pfun2<A1,A2,R>makePFun(R(*pf)(A1, A2))

{return Pfun2<A1,A2,R>(PF);}

//…

std::sort(b,e,makePFun(isGreater));      //好多了…

条款58 重载函数模板

一个函数可以被其他函数模板和非模板函数重载。

条款59 SFINAE

SFINAE(substition failure is neo an error)替换失败并非错误