返回信息流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库中是如何避免此二义性,并正确调用相应构造函数的?
这是一条镜像帖。来源:北邮人论坛 / cpp / #19031同步于 2009/2/7
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖
【求教】C++中函数模板重载问题[已解决]
flyingmiao
2009/2/7镜像同步2 回复
订阅后,新回复会通过你的通知中心匿名送达。
2 条回复
果然读源码是王道,谜底如下,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)是一样的。
这似乎是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)
: {
: ...................