zoukankan      html  css  js  c++  java
  • 转:C++模板特化的概念

    http://blog.csdn.net/yesterday_record/article/details/7304025

    很久没有看C++,在看STL源码剖析时,看到一个function template partial order(偏序模板函数)概念,一时不明白,于是在网上搜罗一下,看完了才明白了就是以前在学校看的《C++ Primer》中的模板特例化相关的概念。这里将搜到的资料整理一下。

    1. 模板的特化
    C++中经常为了避免重复的编码而需要使用到模板,这是C++泛型编程不可或缺的利器。然而通常又有一些特殊的情况,不能直接使用泛型模板展开实现,这时就需要针对某个特殊的类型或者是某一类特殊的类型,而实现一个特例模板————即模板特化。通常会使用到模板特化的有(应该也只能有)类模板和函数模板。

    a. 类模板特化
    在已有类模板
    template <class T>
    class stack { //...// };
    定义时,可能考虑到一些特定的类型T,数据的存储可能和通用模板不一样,因而可以像如下定义一个特例化模板:
    template < >
    class stack<bool> { //...// };

    b. 函数模板的特化
    template <class T>
    T max(const T t1, const T t2)
    {
        return t1 < t2 ? t2 : t1;
    }
    如上已有的模板定义可能在针对一个指针类型的参数时,工作将可能会不正常,具体到字符串指针类型时,可能就需要下面的特例化模板定义:
    template < >
    const char* max(const char* t1,const char* t2)
    {
        return (strcmp(t1,t2) < 0) ? t2 : t1;
    }
    这样才能使max("aaa", "bbb");的调用更如人意(通常没有人想比较两个常量字符串存储的地址的大小)。

    2. 模板的偏特化
    模板的偏特化是指需要根据模板的部分参数进行特化。

    a. 类模板的偏特化
    例如c++标准库中的类vector的定义
    template <class T, class Allocator>
    class vector { // … // };
    template <class Allocator>
    class vector<bool, Allocator> { //…//};
    这个偏特化的例子中,一个参数被绑定到bool类型,而另一个参数仍需要由用户使用时指定。

    b. 函数模板的偏特化
    网上看到有人说:从严格意义上讲,函数模板并不支持偏特化(我对这个不是很理解),但由于可以对函数进行重载,所以可以达到类似于类模板偏特化的效果。
    比如:
    a) template <class T> void f(T);   
       根据重载规则,对a)进行重载
    b) template < class T> void f(T*);   
       如果将a)称为基模板,那么b)称为对基模板a)的重载,而非对a)的偏特化。

    3. 模板特化时的匹配规则
    (1) 类模板的匹配规则
    最优化的优于次特化的,即模板参数最精确匹配的具有最高的优先权
    例如:
    template <class T> class vector{//…//}; // (a) 普通型
    template <class T> class vector<T*>{//…//}; // (b) 对指针类型特化
    template <>    class vector <void*>{//…//}; // (c) 对void*进行特化
    每个类型都可以用作普通型(a)的参数,但只有指针类型才能用作(b)的参数,而只有void*才能作为(c)的参数

    (2) 函数模板的匹配规则
    非模板函数具有最高的优先权。如果不存在匹配的非模板函数的话,那么最匹配的和最特化的函数具有高优先权。
    比如有如下模板:
    template<typename T>
    void func1(T t)
    {
        cout<<"func1 1"<<endl;
    }
     
    template<typename T>
    void func1(T* t)
    {
        cout<<"func1 2"<<endl;
    }
     
    template<typename T>
    void func2(T t)
    {
        cout<<"func2"<<endl;
    }

    编译器判段两个函数模板谁比谁更特化的方法是尝试,编译器自己生成内部类型A,把它分别代入函数func1的模板,比如编译器如下构造{A a}现在就有了如下两个函数

    func1(a); //这个利用第一个模板代入
    func1(a*);//这个利用第二个模板代入

    现在编译器把这两个反向,把a代码第二个模板,把a*代入第一个模板,显然第一个模板函数是可以接受指针类型的,让T为a*就可以了;

    但是第二个模板函数不能接收a,因为它的参数必须是一个指针。由此编译器知道第一个函数模板比第二个函数模板更加泛化,也就是说第二个函数模板比第一个函数模板更加特化。


    好像在《C++ Primer》中有类似如下的描述:

    C++中,函数模板与同名的非模板函数重载时,应遵循下列调用原则:

    a. 寻找一个参数完全匹配的函数,若找到就调用它。若参数完全匹配的函数多于一个,则这个调用是一个错误的调用。

    b. 寻找一个函数模板,若找到就将其实例化生成一个匹配的模板函数并调用它。

    c. 若上面两条都失败,则使用函数重载的方法,通过类型转换产生参数匹配,若找到就调用它。

    d. 若上面三条都失败,还没有找都匹配的函数,则这个调用是一个错误的调用。

    总结:

    1. 模板的特化是在已有的通用模板不再适用于一些特殊的类型参数时,而针对这些特殊的类型参数专门实现的模板。

    2. 模板的偏特化是指需要根据模板的部分参数进行特化。

    3. 函数调用匹配的规则是:先精确匹配类型参数,然后匹配函数模板,最后通过参数隐式类型转换进行匹配。

     

  • 相关阅读:
    [Powershell]导出指定的定时计划任务
    [Powershell]发布基于.NET Framework的WebAPI和Job控制台程序项目
    [Powershell]使用Msbuild构建基于.NET Framework的WebAPI项目
    [最新].NET Core ORM 开源项目一览,持续更新
    【最新】Xmanager Power Suite 6.0 Build 0017
    Git抽取版本之间的差异,打包解压
    PuppeteerSharp+AngleSharp的爬虫实战之汽车之家数据抓取
    PostgreSql之在group by查询下拼接列字符串
    同事问如何判断同花顺,我用javascript的二维数组写了个简易demo
    Gitlab定义安全变量遇到无法转义的字符——感叹号
  • 原文地址:https://www.cnblogs.com/zendu/p/5948772.html
Copyright © 2011-2022 走看看