一个模板函数的重载问题~
Eastsun
2007-11-29
RT,下面这段代码为什么编译通不过?
#include<iostream> using namespace std; /** * 为什么这段代码编译出错?? */ template<typename T> void print(T value); int main(){ print(1); } template<typename T> void print(T value){ cout<<"template<typename T> :"<<value<<endl; } template<> void print<int>(int i){ cout<<"template<> :"<<i<<endl; } void print(int i){ cout<<"simple :"<<i<<endl; } 改成这样就没问题: #include<iostream> using namespace std; template<typename T> void print(T value){ cout<<"template<typename T> :"<<value<<endl; } template<> void print<int>(int i){ cout<<"template<> :"<<i<<endl; } void print(int i){ cout<<"simple :"<<i<<endl; } int main(){ print(1); } |
|
jimmy_c
2007-11-30
跟template没关系吧。你的void print(int i)没有声明,当然编不过。
|
|
Eastsun
2007-11-30
如果是ls所说的原因,那为什么这样又可以编译通过呢?
#include<iostream> using namespace std; template<typename T> void print(T value); int main(){ print(1); } template<typename T> void print(T value){ cout<<"template<typename T> :"<<value<<endl; } void print(int i){ cout<<"simple :"<<i<<endl; } |
|
jimmy_c
2007-11-30
前面说的不够准确。
这应该是个c/c++的普遍性问题,是因为代码顺序造成的。和你的 void print(int i) {} 声明与否没有关系。这段代码完全可以删掉。 和template也没有太大关系。 第一种写法,因为 template<> void print<int>(int i) {} 的实现写在main()之后,编译器在编译main的时候是不知道有这个函数特化实现的,所以使用的是 template<typename T> void print(T value) 版本的实现,因为前面有它的声明。而编译器这时候就会做一个模板实例化的工作,全局查找到 template<typename T> void print(T value) 的实现,把实现中的T用int替换,自动生成一个int版本的模板函数,也就是 template<> void print<int>(int value)。 但是接下来往下编译,它会发现另一个版本的 template<> void print<int>(int value),所以就会有同名函数的冲突问题。 |
|
jimmy_c
2007-11-30
这个问题引申一下,模板函数和“实”函数编译器处理上的区别。如果上面的程序写成:
template<typename T> void print(T value); template<typename T> void func() { print(1); } template<typename T> void print(T value) { cout<<"template<typename T> :"<<value<<endl; } template<> void print<int>(int i) { cout<<"simple :"<<i<<endl; } int main() { func<int>(); return 0; } 结果就是对的,因为func<T>是个模板函数,编译器编译时会查找print<T>的对应版本。能否找到我想应该和调用func()的位置有关。而把func<T>的模板参数去掉,编译结果就不正确,虽然这个模板参数并没有什么意义。因为对于“实”函数,编译器会认为它所需要的函数应该在它前面声明。 我想产生这个结果的原因应该是编译器模板实例化的时刻吧!编译器会在需要实例化的时候去产生模板的实例函数,所以“调用点”的位置应该很有关系。 |
|
jimmy_c
2007-11-30
另外,对于
template<> void print<int>(int i) 和 void print(int i) 编译器会认为它们是两个不同的函数,C++标准对于模板函数匹配的情况是有一个优先级顺序的,试验的结果似乎是先匹配实函数,再匹配模板函数。当然前提是声明要在调用的前面。 |
|
Eastsun
2007-11-30
嗯,按楼上所说,那为什么下一种写法又能编译通过呢?
#include<iostream> using namespace std; template<typename T> void print(T value); template <> void print<int>(int); int main(){ print(1); } template<typename T> void print(T value){ cout<<"template<typename T> :"<<value<<endl; } template <> void print<int>(int v){ cout<<"template<> :"<<v<<endl; } void print(int i){ cout<<"simple :"<<i<<endl; } 而且这段代码运行的结果是: template<> :1 按照LS的推理,我声明了 template <> void print<int>(int); 但没有声明 void print(int i) 所以main中的函数使用的是template <> void print<int>(int); 但接着往下编译,它会发现另一个版本的 void print(int i); 而且在编译器中,这个版本的优先级更高. 所以应该有同名函数冲突才对. 但结果不是这样的,为什么呢? ps:不管怎么样,非常感谢LS的讨论. 另外,这个问题是我阅读<C++ prime>第四版的中文版的231页时产生的. |
|
Eastsun
2007-11-30
哦,没看到LS刚刚发的
|
|
Eastsun
2007-11-30
我想知道的是
对于这个问题有没有一个官方的说法,比如C++标准里面. 我觉得C++最恶心的地方就在于: 没有一个完全符合标准的编译器. 如果写代码出问题了,有可能是自己写错了,也可能是编译器对C++当前标准支持不够,甚至可能是像VC一样的非标准C++造成的. |
|
Eastsun
2007-11-30
还有,我想知道:
现在对于调用 print(1)来说,它有三种实现方式. <C++ Prime>里面说的是普通函数优先级>显式具体化>模板实现. 那么,在三个实现都可见的情况下,使用print(1)会使用普通的实现. 而使用print<int>(1)会调用显式具体化那个实现. 那如果我想调用模板那个实现该怎么办呢? <C++ prime>里面提到声明时可以指定的,也就是这样: template void print<int>(int); 声明,就会使用模板实现. 但事实上这样编译不过去.why? |