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. 函数调用匹配的规则是:先精确匹配类型参数,然后匹配函数模板,最后通过参数隐式类型转换进行匹配。

 

转:C++模板特化的概念的更多相关文章

  1. C++-函数模板特化如何避免重复定义

     我正在用一个基于模板的库源代码,该库包含一些针对特定类型的模板函数特化.类模板,函数模板和模板函数特化都在头文件中.我在我的.cpp文件中 #include 头文件并编译链接工程.但是为了在整个工程 ...

  2. C++ template —— 模板特化(五)

    本篇讲解模板特化-------------------------------------------------------------------------------------------- ...

  3. C++模板之隐式实例化、显示实例化、隐式调用、显示调用和模板特化详解

    模板的实例化指函数模板(类模板)生成模板函数(模板类)的过程.对于函数模板而言,模板实例化之后,会生成一个真正的函数.而类模板经过实例化之后,只是完成了类的定义,模板类的成员函数需要到调用时才会被初始 ...

  4. C++ Primer 学习笔记_84_模板与泛型编程 --模板特化

    模板与泛型编程 --模板特化 引言: 我们并不总是能够写出对全部可能被实例化的类型都最合适的模板.某些情况下,通用模板定义对于某个类型可能是全然错误的,通用模板定义或许不能编译或者做错误的事情;另外一 ...

  5. C++ Primer 学习笔记_85_模板与泛型编程 --模板特化[续]

    模板与泛型编程 --模板特化[续] 三.特化成员而不特化类 除了特化整个模板之外,还能够仅仅特化push和pop成员.我们将特化push成员以复制字符数组,而且特化pop成员以释放该副本使用的内存: ...

  6. C++程序设计方法4:模板特化

    模板参数的具体化/特殊化 有时,有些类型不适用,则需要对模板进行特殊化处理,这称为“模板特化” 对函数模板,如果有多个模板参数,则特化时必须提供所有参数的特例类型,不能部分特化: 如: char *s ...

  7. C++ 模板特化以及Typelist的相关理解

    近日,在学习的过程中第一次接触到了Typelist的相关内容,比如Loki库有一本Modern C++ design的一本书,大概JD搜了一波没有译本,英文版600多R,瞬间从价值上看到了这本书的价值 ...

  8. oop &&GP 模板 ---> 特化和偏特化

    OOP面向对象编程 GP泛型编程(generic programming) 两者的主要区别就是OOP将数据和对数据的操作放在一起, GP就是将数据和操作独立开来 GP:   数据就是container ...

  9. C++模板特化编程

    在C++中,模板特化是除了类之外的一种封装变化的方法.模板特化可以通过编译器来对不同的模板参数生成不同的代码. 模板特化通常以模板结构体作为载体.常用技法包括:类型定义.静态成员常量定义和静态成员函数 ...

随机推荐

  1. Seaborn相关

    Seaborn:基于Matplotlib,seaborn提供许多功能,比如:内置主题.颜色调色板.函数和提供可视化单变量.双变量.线性回归的工具.其能帮助我们构建复杂的可视化. ————————缩写定 ...

  2. oracle 建立新的表空间

    创建数据表空间 注意粗斜体部分 create tablespace 表空间名称logging datafile 'D:\app\Administrator\oradata\orcl\XXXX.dbf' ...

  3. PAT 天梯赛 L1-041. 寻找250 【水】

    题目链接 https://www.patest.cn/contests/gplt/L1-041 AC代码 #include <iostream> #include <cstdio&g ...

  4. HDU - 1151 Air Raid (最小路径覆盖)

    题意:给定一个有向无环图,求最少划分几条路径,使之能够覆盖所有点. 分析:这可以转化为DAG上的最小路径覆盖问题. 路径覆盖的定义:有向图中,路径覆盖就是在图中找一些路径,使之覆盖了图中的所有顶点,且 ...

  5. 无线安全之破解WPA/WPA2 加密WiFi

    准备 可以使用无线网络的Kali Linux 由于古老的WPE加密的WiFi已经几乎没有了,所以这里我就不去细说如何破解WPE加密的WiFi了.今天就来聊聊 如何来使用Kali Linux来破解Wpa ...

  6. CreateWindow创建无边框 可拉伸窗体

    createwindow 定义 HWND WINAPI CreateWindow( _In_opt_ LPCTSTR lpClassName, _In_opt_ LPCTSTR lpWindowNam ...

  7. centos 7 install virtualbox

    from:https://wiki.centos.org/HowTos/Virtualization/VirtualBox Installing VirtualBox cd /etc/yum.repo ...

  8. 20145222 黄亚奇 《网络对抗》Exp8 Web基础

    20145222 黄亚奇 <网络对抗>Exp8 Web基础 实践具体要求 (1).Web前端HTML(1分) 能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法 ...

  9. C++中int转为char 以及int 转为string和string 转int和字符串的split

    1.对于int 转为char 直接上代码: 正确做法: void toChar(int b) { char u; ]; _itoa( b, buffer, ); //正确解法一 u = buffer[ ...

  10. Win32 API编程:网络编程在设置WSAAsyncSelect模型后connect的返回值问题

    通过WSAAsyncSelect()可以设置非阻塞异步套接字 ::WSAAsyncSelect(s, hDlg, WM_SOCKET, FD_CONNECT | FD_CLOSE | FD_WRITE ...