《c++ templates》学习笔记(4)——第五章,技巧性基础知识

 

1       第五章 技巧性基础知识

1.1    关键字typename

在标准化c++的过程中,引入typename是为了说明:模板内部的标识符可以是一个类型。下面举个例子:

template<typename T>

class MyClass{

     typename T::SubType * ptr;

     ..

};

1.1.1    .templates构造

这个比较生僻一些,给个例子吧

template<int N>

void printBitset(std::bitset<N> const& bs)

{

     std::cout<<bs.template to_string<char, std::char_traits<char>, std::allocator<char> >();

}

只有在编译器判断小于号(<)之前,存在依赖于模板的构造,才会出现这种问题。

 

1.2    使用this->

这个暂时不是很明白,需要等看了9.4.2小结之后再来弄明白

 

1.3    成员模板

类成员也可以是模板,嵌套类和成员函数都可以作为模板。下面通过Stack<>的赋值运算符来索命这种能力的应用方法。

template<typename T>

class Stack{

     ...

public:

     template<typename T2>

     Stack<T>& operator=(Stack<T2> const&);

};

 

template<typename T>

template<typename T2>

Stack<T>& Stack<T>::operator=(Stack<T2> const& op2)

{

     ...

}

此处需要注意成员模板函数的声明和定义。

 

1.4    模板的模板参数

关于这个名词,以前一直没有理解。其实现在看来也比较简单,就是作为模板参数的参数,在定义的时候,就约定这个参数一定要是一个模板。

需要说明的是,vc6不支持该特定,vc7开始就支持了。

有了模板的模板参数之后,原来需要这样写的代码:

Stack<int, std::vector<int> > vStack;

现在可以改为这样:

Stack<int, std::vector> vStack;

所以在我看来,这个特性没有太大的用处,而且对于定义模板的人来说,还会增加很多的工作量。

原来的:

template<typename T, typename CONT=std::vector<T> >

class Stack{

     ...

};

现在就要改成:

template<typename T, typename <typename ELEM> class CONT=std::deque >

class Stack{

     ...

};

这还只是声明,在定义处还有许多烦人的东西。

 

这里由于我们没有用到ELEM,所以可以ELEM可以省略。

 

上面的这个class不能替换为typename

1.4.1   模板的模板实参匹配

如果你尝试去编译上面提供的代码,就发发现有编译错误,这里涉及到一个模板的模板实参匹配问题。

如果模板的模板实参(譬如这里的std::deque)是一个具有参数A的模板,他将替换模板的模板参数(这里的CONT),而模板的模板参数是一个具有参数B的模板(这里为ELEM),匹配的过程要求参数A和参数B完全匹配;然而这里我们并没有考虑模板的模板实参的缺省模板参数,从而也就使B中缺少了这些参数值,当然也就无法精确匹配。

1.5    零初始化

任何未被初始化的局部变量都是一个不确定值。

所以,对于类模板内部的成员,最好在构造函数内的初始化列表内初始化这些成员。

 

1.6    使用字符串作为函数模板的实参

有时,把字符串传递给函数模板的引用参数会导致出人意料的运行结果。

template<typename T>

inline T const& max(T const& a, T const& b)

{

     return a<b?:a;

};

 

int _tmain(int argc, _TCHAR* argv[])

{

     std::string s;

     ::max("apple", "peach"); //OK

     ::max("apple", "tomato");//ERROR

     ::max("apple", s);     //ERROR

     return 0;

}

对于其中

::max("apple", "tomato");//ERROR

为什么会出错,可能会有很多人不理解,我一开始也不理解,所以这里重点说明。

由于长度的区别,这些字符串属于不同的数组类型。也就是说,”apple””peach”具有相同的类型 char const[6];然而,”tomato”的类型则是:char const[7]。因此,只有第一个调用是合法的。

        如果改为非引用的参数,你就可以使用长度不同的字符串来作为max()的参数。

 

       产生这种结果的原因:对于非引用类型的参数,在实参演绎的过程中,会出现数组到指针的decay

        以后如果你遇到一个关于字符数组和字符穿指针之间不匹配的问题,你会意外地发现和这个问题有一定的相似之处。

原文地址:https://www.cnblogs.com/strinkbug/p/1335468.html