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/m.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燈, 水草

請輸入看板名稱,例如:Boy-Girl站內搜尋

TOP