c++模板函数实例化的偏序机制
一:废话
今天在stackoverflow上看到一个关于c++模板specialization的问题:
他的English好像不是很标准(说不定是India三哥,哈哈),但比我强多了。废话不多说,问题简述如下:
- //#1
- template<class X> void foo(X a)
- {
- cout << "Template 1" << endl;
- }
- //#2
- template<class X> void foo(X *a)
- {
- cout << "Template 2" << endl;
- }
现在如果定义一个特例化函数如下:
- template<> void foo<>(int *a)
- {
- cout << "Specialization 1" << endl;
- }
那么这哥们的问题如下:
1 这个函数是属于template #1呢还是属于template #2呢?
2 如果这个特例化定义在template #2之前和之后,结论会有差别吗?
其实看过c++模板的内容,但没怎么用过复杂的模板,只是简单的写一些模板函数,方便适应不同的参数。 所以对模板特例化没有特别深入了解, 对偏序机制也就没有什么概念。正巧遇到这个哥们问了这样一个问题,我试着去回答,但是无能为力,正好有一位大神帮他回答了,于是我也顺便请教了这位大神,他说这个偏序化机制在模板中是一个比较复杂的概念,涉及内容比较多。了解了这个以后,我Google了一点资料,写下这篇小心得。
二: 偏序化(Partial Ordering)
应该是这么翻译吧!先看下什么叫partial ordering?引用参考资料1里面的介绍:
- A function template specialization might be ambiguous because template argument deduction might associate the specialization with
- more than one of the overloaded definitions. The compiler will then choose the definition that is the most specialized. This process of selecting a function template definition is called partial ordering
三: 介绍
在介绍之前,先看看什么叫最特例化?举个例子:
- //#1
- template<class T> void f(T);
- //#2
- template<class T> void f(T*);
- //#3
- template<class T> void f(const T*);
上述三个模板中,特例化的程度从大到小依次为:
- #3 > #2 > #1
如果现在有这样一个调用:
- int *p = NULL;
- f(p);
那么编译器肯定会选择#2模板,而不是#1模板,因为#2模板比#1模板更特例化。为什么不选#3模板?因为还有一个规则,优先选择类型显式匹配的模板,如果调用#3号模板,需要隐式转换。
然后,接下来的问题是:编译器怎么知道#2模板比#1模板更特例化?下面就是我要说的partial ordering。编译器通过如下的方法来判断:
- 1 先选择两个函数模板,T1和T2
- 2 用假设的唯一类型X取代模板T1的参数
- 3 用被X取代后的T1的参数列表,带入T2,看T2是否是一个有效的模板。忽略所有的隐式转换。
- 4 反过来,先用X取代T2的参数,再把T2的参数列表带入T1,看看T1是否有效。
- 5 如果一个模板的参数比如T1对于另外一个模板T2是有效的,但是反之不成立,那么就说这个模板T1不比T2更特例化。如果这两个模板的参数都可以相互代替,就说它们具有相同的特例性,这样会引起编译器混淆。
举两个会引起混淆的一个例子,比如:
- template<class T> void g(T) { }
- template<class T> void g(T&) { }
- template<class T> void h(T) { }
- template<class T> void h(T, ...) { } //error C2668: 'h' : ambiguous call to overloaded function
可变参数不会引起编译器执行partial ordering规则,所以这两种模板也会引起歧义。
四:使用
partial ordering的判断实例:
- 1 对于一个模板,特定类型的参数比一般类型的参数,更具有特例性
- 2 带有T*的模板比T的模板具有特例性。因为一个假设的类型X*也可以被认为是T类型的, 相反一个有效的T类型参数,可能不是X*类型的。
- 3 const T比T更特例化,道理同上。
- 4 const T*比const T更特例化,理由也是一样的。
举个例子:
- template <class T> void f(T) {
- cout<<"f(T):Less specialized function called"<<endl;
- }
- template <class T> void f(T*) {
- cout<<"f(T*):More specialized function called"<<endl;
- }
- template <class T> void f(const T*) {
- cout<<"f(const T*):Even more specialized function for const T*"<<endl;
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- int i =;
- const int j = ;
- int *pi = &i;
- const int *cpi = &j;
- f(i); // Calls less specialized function.
- f(pi); // Calls more specialized function.
- f(cpi); // Calls even more specialized function.
- // Without partial ordering, these calls would be ambiguous.
- }
什么情况下,编译器会执行这样的一个Partial Ordering?文献1给出了几种情况:
- · Calling a function template specialization that requires overload resolution.
- · Taking the address of a function template specialization.
- · When a friend function declaration, an explicit instantiation, or explicit specialization refers to a function template specialization.
- · Determining the appropriate deallocation function that is also a function template for a given placement operator new.
(1) 调用函数模板特例时,涉及到重载决议
(2) 获取函数模板特例的地址
(3) 当一个友元函数声明,或者显示实例化,或者引用函数模板的显示特例化
(4) 对一个new出来的内存进行销毁时(这个new函数也是模板函数),如何选择相应的释放函数也会引发partial ordering。
REFERENCE:
c++模板函数实例化的偏序机制的更多相关文章
- 使用 c++ 模板显示实例化解决模板函数声明与实现分离的问题
问题背景 开始正文之前,做一些背景铺垫,方便读者了解我的工程需求.我的项目是一个客户端消息分发中心,在连接上消息后台后,后台会不定时的给我推送一些消息,我再将它们转发给本机的其它桌面产品去做显示.后台 ...
- C++:函数模板与模板函数
6.1 模板的概念 C++允许用同一个函数定义函数,这些函数的参数个数和参数类型不同.例如求最大值的max函数, int max(int x,int y) { return (x>y ...
- [C++]模板类和模板函数
参考: C++ 中模板使用详解 C++模板详解 概念 为了避免因重载函数定义不全面而带来的调用错误,引入了模板机制 定义 模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模 ...
- [转]C++函数模板与模板函数
1.函数模板的声明和模板函数的生成 1.1函数模板的声明 函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计.它的最大特点是把函数使用的数据类型作为参数. ...
- 模板函数(template function)出现编译链接错误(link error)之解析
总的结论: 将template function 或者 template class的完整定义直接放在.h文件中,然后加到要使用这些template function的.cpp文件中. 1. 现 ...
- C++ 模板函数与模板类
一.模板函数 函数模板提供了一类函数的抽象,即代表了一类函数.当函数模板被实例化后,它会生成具体的模板函数.例如下面便是一个函数模板:
- 为什么模板函数的声明和实现都放在.h文件中
当你不使用这个模板函数或模板类,编译器并不实例化它,当你使用时,编译器需要实例化它,因为编译器是一次只能处理一个编译单元,也就是一次处理一个cpp文件,所以实例化时需要看到该模板的完整定义.所以都放在 ...
- [c++][语言语法]函数模板和模板函数 及参数类型的运行时判断
参考:http://blog.csdn.net/beyondhaven/article/details/4204345 参考:http://blog.csdn.net/joeblackzqq/arti ...
- C++ template学习一(函数模板和模板函数)
函数模板和模板函数(1)函数模板函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计.它的最大特点是把函数使用的数据类型作为参数.函数模板的声明形式为:templat ...
随机推荐
- 我的c++学习(11)数组和指针
使用数组显示斐波那契数列 #include "stdafx.h" using namespace std; #include<iostream> int _tmain( ...
- 洛谷 P1204 [USACO1.2]挤牛奶Milking Cows Label:模拟Ex 74分待查
题目描述 三个农民每天清晨5点起床,然后去牛棚给3头牛挤奶.第一个农民在300秒(从5点开始计时)给他的牛挤奶,一直到1000秒.第二个农民在700秒开始,在 1200秒结束.第三个农民在1500秒开 ...
- Tornado 学习笔记13 TCPServer
为了实现TCPServer的功能,定义一个类用于继承TCPServer并实现handle_stream方法.HttpServer就是一个很好的例子. 13.1 构造函数 def __init ...
- Glyphicon 字体图标
Bootstrap中的Glyphicon 字体图标 在Bootstrap框架中也为大家提供了近200个不同的icon图片,而这些图标都是使用CSS3的@font-face属性配合字体来实现的icon效 ...
- Coreseek 安装指南
Coreseek 中文官网:http://www.coreseek.cn/ Sphinx0.9.9 中文手册:http://www.coreseek.cn/docs/coreseek_3.2-sphi ...
- python: DOM 小实例
一.全选 全部取消 反选 全选:选择指定的所有项目. 全部取消: 取消所有选定的项目. 反选: 选择未选定的,之前已选定的则取消. <!DOCTYPE html> <html la ...
- PHP 学习笔记---基本语法
------php语言与JavaScript的使用 方法是相似 <script type="text/javascript"> </script>--js与 ...
- curl 传递用户session
$cmh = curl_multi_init(); $ch = curl_init(); curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch, CU ...
- [IT新应用]家用NAS,自建“360云盘”
360云盘也快要离开了.同事中有人开始尝试使用群晖NAS.西数的NAS来自建云了. [功能对比] [选择参数] [口碑评价]
- Yii源码阅读笔记(三十二)
web/Application类的注释,继承base/Application类,针对web应用的一些处理: namespace yii\web; use Yii; use yii\base\Inval ...