zoukankan      html  css  js  c++  java
  • 《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

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

  • 相关阅读:
    学习笔记 MYSQL报错注入(count()、rand()、group by)
    学习笔记 HTTP参数污染注入
    学习笔记 MSSQL显错手工注入
    代码审计入门后审计技巧
    字符串的排列
    二叉搜索树与双向链表
    复杂链表的复制
    二叉树中和为某一值的路径
    二叉搜索树的后序遍历序列
    从上往下打印二叉树
  • 原文地址:https://www.cnblogs.com/strinkbug/p/1335468.html
Copyright © 2011-2022 走看看