C_and_CPP 板


LINE

※ 引述《moebear (萌熊)》之铭言: : 开发平台(Platform): (Ex: Win10, Linux, ...) : win10/linux : 编译器(Ex: GCC, clang, VC++...)+目标环境(跟开发平台不同的话需列出) : GCC/VC++ : 额外使用到的函数库(Library Used): (Ex: OpenGL, ...) : 问题(Question): : 请问程式码中第6/22/28行,这三个ostream之间的关联性是什麽? : 25行以上是助教给的程式码,但是我寄信问助教,他只说这是约定俗成的写法 囧。 : 1.为什麽第6行是必备的? 我的理解中,提前宣告是因为实作在後面,中间可能有人用到 : 但是中间到底是谁用到呢? 22行吗? 那为什麽22行会需要用到第6行的宣告呢? : 2.第22行的<>是什麽意思呢? 我觉得看起来很像是某种template, : 但是中间又不能塞T进去。 : 3.第28行是我自己写的,我试过很多方法, : 但是好像只有这样写才可以,跟他关联的好像是第6行,而不是第22行。 : 总之就是这三行之间的关系,以及为什麽22行要这样写? 先讲结论: 根本原因是 CirDequeTemplate 是一个 template class 的关系 如果你只是在写一个非 template class 的 ostream << operator 的话 事情其实很简单: class IntCirDeque { //... friend ostream& operator << (ostream&, const IntCirDeque&); }; ostream& operator << (ostream& out, const IntCirDeque& icd) { //... } 这样就行了, 甚至那行 friend 还能充当前置宣告使用 也就是对只引用 IntCirDeque 定义而没有 operator << 实作的地方也能呼叫它 (有个限制就是: 它要能被 ADL 找到才行, 这里显然 ADL 能找得到 不过这跟原问题无关就表过不提) 关於这种写法的细节你应该清楚, 例如为什麽它要是非成员再写 friend, 这里略过 ==== 那麽为什麽当挂上 template 事情就有点微妙的不一样了? 首先, 先看你的实作 (#27~#28): template<class T> std::ostream & operator<< (std::ostream &s, const CirDequeTemplate<T> &cird) 你应该在尝试时注意到了, 因为 cird 是一个 template class 你必须要对每个 T 都要能产生一份这个 operator 才行 如你所观察到的, 跟它相关的是 #6 事实上你这两行扣掉变数名其实是必须要跟 #6 一模一样才行 这正是在达成上面提的「对每个 T 都要能产生一份这个 operator」 这个写法其实就只是一个普通的 template 函数的写法而已 跟 template class 一样, 在前面挂上 template <class T> 然後下面用 T 代换 到这里应该回答了你的问题 3 (一个题外话, 你这里的实作不能用 printf, 因为当 T 不是 int 时就爆了 你应该要 << 进那个 ostream& 里面, 跟 cout 一样的用法只不过 cout 换成这个参数 是说你都在学 C++ 了为什麽还写 printf...) ==== 刚才提到「对每个 T 都要能产生一份这个 operator」 所以 class 里面宣告 friend 时必须要宣告 「有跟我一样的 T 的 operator << 是我的朋友」 这里需要提一个你应该也知道的规则: 单独 template 名并不是一个完整的名字, 它一定要有办法知道它的 <> 里是什麽型别 在大多数时候 <> 都不能省略, 否则编译器不会知道这个名字是个 template 名 就算你的 <> 里要用其他资讯推导也是一样 <> 能省略的地方只有你在自己里面指名自己时可以省略 (我知道这里有人要提 template 函数呼叫, 那个最後提) (这里还必须要真的是指名自己, 也就是 template 参数都要一模一样才行 如果不一样那就还是得乖乖写出来) 这就是这里的 <> 的用途: 表示这个 operator << 是一个 template 名字 那 <> 里面的东西也不必每次都一一指定, 能够推导的就能省略 这个状况里这里面是可以塞 T 的: friend ostream& operator << <T> (ostream&, const CirDequeTemplate<T>&); 即是重覆一次 #6 / #28 的宣告 只不过把宣告用的前置 template <class T> 换成指名用的後置 <T> 但是这个 T 其实是可以从参数推导出来的: 这个宣告的第二参数是一个自己这种物件, 因此这时的 T 是确定的: 跟我自己一样的 T 因此我们可以省略前面的 operator << <T> 里的 T, 就成了 operator << <> 了 後面的 <T> 是属於上面所说指名自己时可省略的状况, 所以也就不写了 这样就成了 #22 的写法: friend ostream& operator<< <>(ostream&, const CirDequeTemplate&); 以上回答问题 2 ==== 刚才也提到, #22 的写法里的 operator << 是个 template 名 既然是 template 名那在前面就必须要有对应的 template 宣告才能使用 #6 就正是这个 operator << 所需要的前置 template 宣告 有了 #6 的宣告, #22 的 operator << 才能知道是一个 template 名字 才能跟後续的 template 定义连起来 这里你不能像非 template 版本一样把 template 宣告跟 friend 合起来 原因是你所 friend 的只有这特别的一个 operator << 而已, 不是整个 template 以上回答问题 1 同样的理由 #5 为 #6 里的 CirDequeTemplate 这名字进行前置宣告 ==== 因此全部总结起来的话就是这样: #28 为了 template class 所以写成一个单纯的 template 函数 #22 尝试宣告某个特定的 #28 为 friend, 为此需要 #6 前置宣告 #28 的存在 ==== 最後回头解释一下为什麽上面没提 template 函式呼叫做为省略 <> 的状况 这是因为函式呼叫是个不一样的状况 编译器会取出这个名字, 看看有没有一般函数及 template 函数有这名 如果有看到 template 函数, 会尝试推导要用什麽 template 参数才能符合呼叫方型态 所有能推导出来的版本跟(如果找得到的)一般函数再一起进行 overload resolution (是的, 我们可以定义同一个名字有非 template 函数和 template 函数) 也就是说, 函数呼叫这个指名并不是直接指名某个 template 函式定义 因此不是属於「提到 template 名」的状况 (然後顺带一提, C++17 把这个推导推广到 constructor 呼叫也适用了 在 C++17 的文件当中叫做 deduction guide, 这里表过不提) -- Ace Snake Santa Clover Junpei June Seven Lotus 9th man cabin kitchen casino shower operating room laboratory T H E chart captain quarter confinement torture room steam engine room cargo chapel library study incinerator Gigantic Q director office security N O N A R Y archives control laboratory pec treatment garden pantry gaulem bay rec room crew quarters infirmary lounge elevator Tenmyouji Quark Dio G A M E S Luna Phi Sigma Alice Clover K --



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 180.177.29.238
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1496956504.A.217.html ※ 编辑: LPH66 (180.177.29.238), 06/09/2017 05:15:23 ※ 编辑: LPH66 (180.177.29.238), 06/09/2017 05:19:08
1F:→ hunandy14: 呜哇 c++17那个好方便 长知识了 06/09 10:07
2F:推 TianBonBon: 超猛 06/09 11:18
3F:推 moebear: 谢谢! 我懂了 题外话那边是我习惯不好,之後我多加留意 06/09 13:36
4F:推 phishingphi: Effective C++ Item 46 也有类似这里的用法,不过是 06/10 21:50
5F:→ phishingphi: 对 implicit type conversion 的 template 用法。 06/10 21:50
6F:→ phishingphi: 可供有兴趣的人参考。 06/10 21:51
7F:推 xvid: 推 06/15 20:41







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:Soft_Job站内搜寻

TOP