BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / cpp / #19031同步于 2009/2/7
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖

【求教】C++中函数模板重载问题[已解决]

flyingmiao
2009/2/7镜像同步2 回复
template<typename T> void f1(unsigned int a, T b) { cout << "1st\n"; }; template<typename T> void f1(T a, T b) { cout << "2rd\n"; }; int main() { f1(1,2); return 0; } 输出: 2rd 为什么? 我个人估计,可能第一个需要转换(int到unsigned int),所以用了第二个。 实际上我注意到,在标准库vector容器中,避免了这个问题。 譬如以下代码 #include <iostream> #include <memory> #include <vector> #include <string> using namespace std; class MyClass { private: MyClass(); public: int val; MyClass(int x = 0):val(x) { cout << "Constructor of " << val << endl << flush; }; }; int main() { vector<MyClass> arr(5, 0); cin.get(); return 0; } vector<MyClass> arr(5, 0); 成功调用了 vector<T>(size_type n, const T &val) 而不是 template<typename In> vector<T>(In begin, In end) (此声明是我个人猜测的) 这里的问题在于,5和0都是int,适用于第一个构造函数 但第二个构造函数模板中,由于begin和end也是同型,可经由模板实参演绎得出,那么此函数模板同样可以演绎出int型的实例,亦即 vector<>(int begin, int end) 换句话说,第二个函数模板亦可适用于代码中调用的情况。 我自己尝试写了一下模拟代码,情况是,由于第一个构造函数需要转换(由int到size_type),调用了第二个构造函数,而导致错误。 也就是没有达到和STL同样的效果 请问,stl库中是如何避免此二义性,并正确调用相应构造函数的?
订阅后,新回复会通过你的通知中心匿名送达。
2 条回复
flyingmiao机器人#1 · 2009/2/7
果然读源码是王道,谜底如下,vs中的stl源码: template<class _Iter> vector(_Iter _First, _Iter _Last) : _Mybase() { // construct from [_First, _Last) _Construct(_First, _Last, _Iter_cat(_First)); } template<class _Iter> void _Construct(_Iter _Count, _Iter _Val, _Int_iterator_tag) { // initialize with _Count * _Val size_type _Size = (size_type)_Count; _Construct_n(_Size, (_Ty)_Val); } template<class _Iter> void _Construct(_Iter _First, _Iter _Last, input_iterator_tag) { // initialize with [_First, _Last), input iterators _Buy(0); _TRY_BEGIN insert(begin(), _First, _Last); _CATCH_ALL _Tidy(); _RERAISE; _CATCH_END } 通过traits做了个编译期判断(函数重载),也就是说,在STL中, vector<MyClass> arr(5, 0); 调用的实际上是 template<typename In> vector<T>(In begin, In end) 而不是 vector<T>(size_type n, const T &val) 然而vector<MyClass> arr(5, 0);的语义是调用后者,为了达到同样效果 stl封装了一层判断,在 template<class _Iter> vector(_Iter _First, _Iter _Last) 中,通过traits做一个编译期判断(函数重载) 然后分别调用两个_construct函数 正常情况下,会调用 template<class _Iter> void _Construct(_Iter _First,_Iter _Last, input_iterator_tag) 而在vector<MyClass> arr(5, 0);的情况下,会调用 template<class _Iter> void _Construct(_Iter _Count, _Iter _Val, _Int_iterator_tag) 这个函数的代码,实际上和vector<T>(size_type n, const T &val)是一样的。
Bergwolf机器人#2 · 2009/2/23
这似乎是vs和标准不兼容的地方 [609@test]$cat template.cpp #include <iostream> using namespace std; template<typename T> void foo(int a, T b) { cout << "f1\n"; } template<typename T> void foo(T a, T b) { cout << "f2\n"; } int main() { foo(1, 2); return 0; } [609@test]$g++ template.cpp -std=c++98 template.cpp: In function ‘int main()’: template.cpp:16: error: call of overloaded ‘foo(int, int)’ is ambiguous template.cpp:5: note: candidates are: void foo(int, T) [with T = int] template.cpp:10: note: void foo(T, T) [with T = int] 按照c++ templates的说法,上面两个模板需要比较特殊性,使用更特殊的模板 而这两个模板的特殊性是无序的,编译器应该报二义性错误才对 【 在 flyingmiao (amiao) 的大作中提到: 】 : template<typename T> : void f1(unsigned int a, T b) : { : ...................