Chinaunix
标题:
模版参数,有的需要实例化,有的不需要实例化,究竟为什么?
[打印本页]
作者:
asker160
时间:
2012-03-03 11:05
标题:
模版参数,有的需要实例化,有的不需要实例化,究竟为什么?
下面6行程序,实现从标准输入读取一些整数,排序,再输出到标准输出
istream_iterator<int>is(cin);
istream_iterator<int>intEOF;
vector<int>v;
copy(is,intEOF,back_inserter(v));//为什么这里不需要参数实例化
sort(v.begin(),v.end(),greater<int>());
copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
复制代码
我的问题在于,这里有两个copy函数调用,为什么第一个back_inserter(v)不需要对指定参数实现
back_inserter<int>
而第二个copy函数需要去指定int实例化参数给ostream_iterator<int>?
这两个都是返回一个iterator对象啊,他们的源代码如下:
------------------------------------------------------------
template<class Cont>
back_insert_iterator<Cont> back_inserter(Cont& x);
------------------------------------------------------------
template<class _U, class _E = char,
class _Tr = char_traits<_E> >
class ostream_iterator
: public iterator<output_iterator_tag, void, void> {
public:
typedef _U value_type;
typedef _E char_type;
复制代码
这让我觉得很疑惑:
(1)既然模版在实现的时候需要去指定类型,为什么有时候可以不指定?
(2)sort函数的前两个迭代器是int实例化的参数,c++编译器能否自动推导出greater这个functor应该使用int作为实例化参数呢?
模版的类型推导功能在这里似乎没有起到作用啊,还是要我来显示的制定类型?
请各位高手解惑!
作者:
OwnWaterloo
时间:
2012-03-03 11:05
本帖最后由 OwnWaterloo 于 2012-03-03 12:40 编辑
回复
1#
asker160
你与donet8、jeanlove_cu之间有神马基情…… 怎么都在用这段代码……
istream_iterator、vector、greater是
类
模板,copy、back_inserter、sort是
函数
模板。
函数模板可以根据
函数实际参数
推导出
模板实际参数
,但不一定总是能成功。
比如:
template<typename T>
T max(T a, T b) { return a<b? b: a; }
max(12,26); // 两个实际参数类型都是int, 可以推导出这是max<int>(12,26);
max<int>(12,26); // 或者也可以显式指定
max(12,2.6); // 一个实际参数是int,另一个是double,于是无法推导出T
max<int>(12,2.6); // 必须显式指定, 相当于 max(12,static_cast<int>(2.6));
max<double(12,2.6); // 或者 max(static_cast<double>(12), 2.6);
max<double>(12,26); // 即使能推导出,也可以显示指定
复制代码
12,26,2.6是函数的实际参数,int,double是模板的实际参数。
而类模板没有前者,所以没法通过前者推导出后者,只能显式写出模板实际参数。
于是有种技巧…… 最简单的例子是std:: pair。
map<int,int> m;
m.insert(pair<int,int>(12,26) ); // pair是类模板,必须显式写出实际模板参数
m.insert(make_pair(12,26) ); // make_pair是函数模板, 可以通过函数实际参数推导
复制代码
make_pair的实现类似于:
template<typename T,typename U>
pair<T,U> make_pair(T a, U b) { // 通过函数参数a,b推导出类型参数T,U
return pair<T,U>(a,b);
}
复制代码
除了make_pair,back_inserter那一坨也是这种技巧中的函数模板, 类似的还有bind那一坨, ptr_fun神马的……
istream_iterator也可以这么搞…… 不过与pair/make_pair有区别……
pair<int,int>(12,26); // 两个函数实际参数分别对应两个模板实际参数, 后者的信息可以由前者提供。
于是可以 make_pair(12,26);
istream_iterator<int>(); // eof 没有实际参数
istream_iterator<int>(cin); // cin 只能提供source信息 —— 从哪获取数据, 无法提供格式信息 —— 将一系列字符解释为int。
可以类似地实现(但STL里没有):
make_istream_iterator(0);
make_istream_iterator(cin,0);
0仅仅协助make_istream_iterator推导模板参数,make_istream_iterator函数并不使用这个参数。
而sort,STL那个3参数的重载类似这样:
template<typename RanIt,typename F>
void sort(RanIt beg, RanIt end, F cmp) {
...
cmp(a,b);
...
}
bool great(int a, int b) { return a>b; }
sort(v.begin(), v.end(), great); // 可以推导出F=bool (*)(int,int)
复制代码
但greater不行,它是一个类模板。类模板不能作为
实际参数
。
就算是greater<int> 都不行, 不能将类型作为函数实际参数进行函数调用。类似于可以max(12,26),但不能max(int,26);
所以要greater<int>(), 这才是一个值, 可以作为函数实际参数, 推导出F=greater<int>。
也许可以另外实现一个:
sort_by<greater>(v.begin(), v.end() );
先不说究竟能不能实现, 我有点忘了…… 总之这与两参数的sort(v.begin(), v.end() ); 冲突, 得换个名字 sort_by, 而且STL也没有提供这个。
作者:
x5miao
时间:
2012-03-03 11:21
这有什么好奇怪的,因为模板函数的参数可以隐式实例化。
作者:
bruceteen
时间:
2012-03-03 11:43
因为 v 已经包含了vector 和 int 等信息
因为 cin 不包含 int 信息
作者:
asker160
时间:
2012-03-03 20:45
OwnWaterloo 发表于 2012-03-03 12:39
回复 1# asker160
你与donet8、jeanlove_cu之间有神马基情…… 怎么都在用这段代码……
我仔细的读了你的回复。
可是:
pair<int,int>(12,26)这里pair的构造函数,
按照你的说法,"12,26是函数的实际参数,int,double是模板的实际参数。"
似乎也说得过去啊,怎么就不能简写为pair(12,26)呢?<int,int>可以通过12,26来推导出来啊!!!!!!
-------------------------------------------------------------------------------------------------
还有一个小问题:
int main(void){
bool t=greater<int>(2,3);
return 0;
}
这个vc6和vc2010都编译不过,提示:
c:\users\a\documents\visual studio 2010\projects\testfunc\testfunc\testfunc.cpp(9): error C2661: 'std::greater<_Ty>::greater' : no overloaded function takes 2 arguments
with
[
_Ty=int
]
Build FAILED.
作者:
asker160
时间:
2012-03-03 20:51
而且,我也没有看出,pair如何就不能推导出类型了:
template<class T, class U>
struct pair {
typedef T first_type;
typedef U second_type
T first;
U second;
pair();
pair(const T& x, const U& y);
template<class V, class W>
pair(const pair<V, W>& pr);
};
有了构造函数的T&x,U&y,难道不足以推导出T和U是什么吗?
大侠解释一下哈!
作者:
OwnWaterloo
时间:
2012-03-03 20:57
回复
5#
asker160
>> pair<int,int>(12,26)这里pair的构造函数,
>> 按照你的说法,"12,26是函数的实际参数,int,double是模板的实际参数。"
>> 似乎也说得过去啊,怎么就不能简写为pair(12,26)呢?<int,int>可以通过12,26来推导出来啊!!!!!!
是int,int, int,double是在max的例子里的。 12,26是int型字面量, 2.6是double型字面量。
pair(12,26) 你的意思是构造一个pair<int,int> 的临时对象吧? 不行……
make_pair(12,26)可以是因为它是
普通函数
…… 全局的、或者名字空间内的。
而要使用
构造函数
,需要先提及
类型
。 比如
int
(12),
double
(2.6)。
再比如 struct point { int x,y; point(int xx,int yy) : x(xx), y(yy) {} };
就可以point(12,26); 调用point:: point(int xx,int yy) 构造函数。
pair不是类型,pair<int,int>才是…… 貌似这里有个专门的术语,我也忘了…… 暂且将pair<int,int> 想象成 int, point 那样的东西吧……
所以要pair<int,int>(12,26);
>> bool t=greater<int>(2,3);
bool b =
greater<int>()
(2,3);
greater模板
greater<int,int> 类型
greater<int,int>() 构造一个临时对象
greater<int,int>()(2,3) 用该临时对象比较2与3
作者:
asker160
时间:
2012-03-04 13:09
pair不是类型,pair<int,int>才是
----------------------------
高,是在是高。
这个问题被解释的很清楚了,本人顿悟。
谢谢!
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2