• C++模板机制总结


    模板是C++中非常重要的组成部分,之前自己对这块领域一直不太熟悉。最近趁着有时间学习了一下,特此总结。

    首先是函数模板,它的定义方式如例子所示:

    template <typename T>T sum(T a,T b)
    {
    	return a+b;
    }
    

    类也有自己的模板,称为类模板,如下所示:

    template <typename T>class Proxy
    {
    public:
    	typedef T value_type;
    	Proxy();
    	~Proxy();
    	value_type val;
    };
    
    template<typename T> Proxy<T>::Proxy()
    {
    	val=T(10);
    }
    
    template<typename T> Proxy<T>::~Proxy()
    {
    
    }
    

     要特别注意的是,C++中类模板的声明和定义应当放到同一个.h文件下,不能将声明和定义分散在不同的文件中。

    类模板也可以有自己的友元函数和静态变量:

    template <typename>class Proxy;
    template <typename T>bool operator==(const Proxy<T>&,const Proxy<T>&);
    template <typename T>class Proxy
    {
    public:
    	typedef T value_type;
    	Proxy();
    	~Proxy();
    	void printval();
    	friend bool operator==<T>(const Proxy<T>&,const Proxy<T>&);
    	value_type val;
    	static T abc;
    };
    template<typename T> void Proxy<T>::printval()
    {
    	std::cout<<val<<std::endl;
    }
    template <typename T> T Proxy<T>::abc=0;

    无论是模板类还是普通类,都可以有自己的模板函数,编译器会根据具体代码的内容实例化特定的模板成员函数。

    template <typename T>class Proxy
    {
    public:
    	template<typename U>void printNum(U num);
    };
    
    template<typename T>template<typename U>void Proxy<T>::printNum(U num)
    {
    	std::cout<<num<<std::endl;
    }
    

      当我们引用模板函数的时候,编译器利用调用中的函数实参来确定其模板参数,这叫做模板实参推断。但只有有限的几种类型转换会自动地应用于这些实参(const转换、数组或函数指针转换)。拿一段代码来举个例子:

    template <typename T>T sum(T a,T b)
    {
    	return a+b;
    }
    
    sum(10,10.5);//this code is error!
    

    在引用sum的时候,实参一个是int类型,一个是double类型,此时不能像普通函数一样实现类型转换。以上代码在编译器是不通过的。

    而如果先将函数显示实例化,则就可以实现参数类型转换了:

    sum<int>(10,10.5);
    

    当我们不能(或不希望)将模板定义用于某些特定类型时,模板特例化就派上用场了。模板特例化就是一个用户提供的模板实例,它将一个或多个模板参数绑定到特定类型或值上。比如之前定义的sum函数,可以针对Sale_Data类特例化:

    template<>
    Sale_Data sum(Sale_Data a,Sale_Data b)
    {
        Sale_Data c;
        c.index=a.index+b.index;
        return c;
    }       

     这样一来,当我们为Sale_Data调用sum时,编译器就会采用上面这个函数;而不再使用通用的模板函数。

    另外还需要记住typename的使用,如下面例子所示:

    template <typename T>class A
    {
    public:
        struct AS{};     
    };
    
    void test()
    {
        typename A<int>::AS as;  
    }
    

    此时在test函数中,如果我们不加typename,那么编译器无法确认AS到底A中的一种类型还是一种静态变量,因此需要用这种方式来声明。

    例外情况如下所示:

    (1)类模板定义中的基类列表

    template<class T>
    class Derived: public Base<T>::XXX
    {
    ...
    }

    (2)类模板定义中的初始化列表

    Derived(int x) : Base<T>::xxx(x)
    { 
    ...
    }

    为什么这里不需要呢?因为编译器知道这里需要的是类型还是变量,(1)基类列表里肯定是类型名,(2)初始化列表里肯定是成员变量名。

  • 相关阅读:
    意料之外,情理之中,Spring.NET 3.0 版本发布-
    学习究竟是为了什么?
    测量软件应用系统的聚合复杂度【翻译稿】
    关键字New,如阴魂不散
    选择IT事业,意味着终身学习
    华为机试001:字符串最后一个单词的长度(华为OJ001)
    C++版
    C++版
    C++版-剑指offer 面试题6:重建二叉树(Leetcode105. Construct Binary Tree from Preorder and Inorder Traversal) 解题报告
    C++版
  • 原文地址:https://www.cnblogs.com/wickedpriest/p/6123113.html
Copyright © 2020-2023  润新知