【问题标题】:C++ different template methods called on same variableC ++在同一个变量上调用不同的模板方法
【发布时间】:2014-08-06 08:09:06
【问题描述】:
有人能解释一下为什么一次使用方法c(T*),下一次使用d<>(int*)吗?方法 c 和 d 似乎与我相同,我无法弄清楚为什么调用的方法类型不同。
#include <iostream>
using namespace std;
template<typename T>
void c(T){ cout <<"(T)" << endl; }
template<>
void c<>(int*){ cout <<"(int*)" << endl; }
template<typename T>
void c(T*){ cout <<"(T*)" << endl; }
template<typename T>
void d(T){ cout <<"(T)" << endl; }
template<typename T>
void d(T*){ cout <<"(T*)" << endl; }
template<>
void d<>(int*){ cout <<"(int*)" << endl; }
int main(){
int i;
c(&i);
d(&i);
return 0;
}
输出:
(T*)
(int*)
【问题讨论】:
标签:
c++
templates
template-specialization
【解决方案1】:
template <typename T>
void c(T); // 1: function template
template <>
void c<>(int*); // 2: specialization of 1
template<typename T>
void c(T*); // 3: overload of 1
template<typename T>
void d(T); // 4: function template
template<typename T>
void d(T*); // 5: overload of 4
template<>
void d<>(int*); // 6: specialization of 5
// ...
int i;
c(&i); // 3 is more appropriate overload than 1
d(&i); // 5 is more appropriate overload than 4
// and it has the suitable specialization 6
图表:
c d
/ \ / \
overloads 1 (3) 4 (5) |
| | | priority
specializations 2 (6) V
【解决方案2】:
重载解析只选择一个基本模板(或一个非模板函数,如果有的话)。只有在决定选择哪个基本模板并且该选择被锁定后,编译器才会环顾四周,看看是否恰好有该模板的合适特化可用,如果有,那么该特化将被使用。
对于函数c,特化void c<>(int*) 用于void c(T) 重载,而对于d,特化void d<>(int*) 用于void d(T*) 重载。
因此,根据上述解释,首先检查void c(T),并忽略打印出的更好的重载void c(T*)(没有专门化)。对于d,void d(T*) 重载也被锁定,但随后特化 void d(int*) 被记录并被选中。
【解决方案3】:
您只是偶然发现了 C++ 的一个丑陋部分。
在编译过程中,重载解析过程是为当前代码找到最佳重载。它在查找阶段选择的一组函数和函数模板上执行,旨在识别一个(并且只有一个)比其他更好的重载。
对于函数模板,它们分为两组:
而重载解析过程有两个步骤:
- 在常规函数和“基本”函数模板中选择最佳匹配
- 如果在步骤 1 中选择了“base”函数模板,则选择最佳专业化(如果有匹配,否则使用“base”)
在你的两个例子中,最好的“基本”函数是c(T*) 和d(T*),所以这是不同的第二步。为什么?
因为,作为函数模板的特化,函数模板必须先声明。
因此:
-
c<>(int*) 是 c(T) 的专业化
-
d<>(int*) 是 d(T*) 的特化
因此,当c(T*)在步骤1中挑选时,当d(T*) 987654328 d<>(int*)是一个更好的专业化时,没有更好的专业化。
因为这很棘手,专家的建议……是不要使用函数模板专业化。它只是奇怪地与函数模板重载混合在一起。