免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5296 | 回复: 7
打印 上一主题 下一主题

模版参数,有的需要实例化,有的不需要实例化,究竟为什么? [复制链接]

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-03-03 11:05 |只看该作者 |倒序浏览
20可用积分
下面6行程序,实现从标准输入读取一些整数,排序,再输出到标准输出

  1.         istream_iterator<int>is(cin);
  2.         istream_iterator<int>intEOF;
  3.              vector<int>v;
  4.         copy(is,intEOF,back_inserter(v));//为什么这里不需要参数实例化
  5.         sort(v.begin(),v.end(),greater<int>());
  6.         copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
复制代码
我的问题在于,这里有两个copy函数调用,为什么第一个back_inserter(v)不需要对指定参数实现
back_inserter<int>
而第二个copy函数需要去指定int实例化参数给ostream_iterator<int>?
这两个都是返回一个iterator对象啊,他们的源代码如下:
------------------------------------------------------------

  1. template<class Cont>
  2.     back_insert_iterator<Cont> back_inserter(Cont& x);
  3. ------------------------------------------------------------
  4. template<class _U, class _E = char,
  5.         class _Tr = char_traits<_E> >
  6.         class ostream_iterator
  7.                 : public iterator<output_iterator_tag, void, void> {
  8. public:
  9.         typedef _U value_type;
  10.         typedef _E char_type;
复制代码
这让我觉得很疑惑:
(1)既然模版在实现的时候需要去指定类型,为什么有时候可以不指定?
(2)sort函数的前两个迭代器是int实例化的参数,c++编译器能否自动推导出greater这个functor应该使用int作为实例化参数呢?
模版的类型推导功能在这里似乎没有起到作用啊,还是要我来显示的制定类型?

请各位高手解惑!

最佳答案

查看完整内容

回复 1# asker160 你与donet8、jeanlove_cu之间有神马基情…… 怎么都在用这段代码……istream_iterator、vector、greater是类模板,copy、back_inserter、sort是函数模板。函数模板可以根据函数实际参数推导出模板实际参数,但不一定总是能成功。比如:12,26,2.6是函数的实际参数,int,double是模板的实际参数。而类模板没有前者,所以没法通过前者推导出后者,只能显式写出模板实际参数。于是有种技巧…… 最简单的例子是std:: ...

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
2 [报告]
发表于 2012-03-03 11:05 |只看该作者
本帖最后由 OwnWaterloo 于 2012-03-03 12:40 编辑

回复 1# asker160

你与donet8、jeanlove_cu之间有神马基情……  怎么都在用这段代码……


istream_iterator、vector、greater是模板,copy、back_inserter、sort是函数模板。
函数模板可以根据函数实际参数推导出模板实际参数,但不一定总是能成功。

比如:

  1. template<typename T>
  2. T max(T a, T b) { return a<b? b: a; }

  3. max(12,26); // 两个实际参数类型都是int, 可以推导出这是max<int>(12,26);
  4. max<int>(12,26); // 或者也可以显式指定

  5. max(12,2.6); // 一个实际参数是int,另一个是double,于是无法推导出T
  6. max<int>(12,2.6); // 必须显式指定, 相当于 max(12,static_cast<int>(2.6));
  7. max<double(12,2.6); // 或者 max(static_cast<double>(12), 2.6);

  8. max<double>(12,26); // 即使能推导出,也可以显示指定
复制代码
12,26,2.6是函数的实际参数,int,double是模板的实际参数。


而类模板没有前者,所以没法通过前者推导出后者,只能显式写出模板实际参数。
于是有种技巧……  最简单的例子是std:: pair。

  1. map<int,int> m;
  2. m.insert(pair<int,int>(12,26) ); // pair是类模板,必须显式写出实际模板参数
  3. m.insert(make_pair(12,26) ); // make_pair是函数模板, 可以通过函数实际参数推导
复制代码
make_pair的实现类似于:

  1. template<typename T,typename U>
  2. pair<T,U> make_pair(T a, U b) { // 通过函数参数a,b推导出类型参数T,U
  3.       return pair<T,U>(a,b);
  4. }
复制代码
除了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参数的重载类似这样:

  1. template<typename RanIt,typename F>
  2. void sort(RanIt beg, RanIt end, F cmp) {
  3.       ...
  4.       cmp(a,b);
  5.       ...
  6. }

  7. bool great(int a, int b) { return a>b; }
  8. 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也没有提供这个。

论坛徽章:
0
3 [报告]
发表于 2012-03-03 11:21 |只看该作者
这有什么好奇怪的,因为模板函数的参数可以隐式实例化。

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
4 [报告]
发表于 2012-03-03 11:43 |只看该作者
因为 v 已经包含了vector 和 int 等信息
因为 cin 不包含 int 信息

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
5 [报告]
发表于 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.

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
6 [报告]
发表于 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是什么吗?

大侠解释一下哈!

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
7 [报告]
发表于 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

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
8 [报告]
发表于 2012-03-04 13:09 |只看该作者
pair不是类型,pair<int,int>才是
----------------------------
高,是在是高。
这个问题被解释的很清楚了,本人顿悟。

谢谢!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP