[問題] 如何只特化參數類別的其中一個函式
看板C_and_CPP (C/C++)作者alan23273850 (God of Computer Science)時間1年前 (2023/02/11 00:26)推噓5(5推 0噓 52→)留言57則, 4人參與討論串1/1
開發平台(Platform): (Ex: Win10, Linux, ...)
Ubuntu 20.04
編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出)
g++
額外使用到的函數庫(Library Used): (Ex: OpenGL, ...)
問題(Question):
給定一個 template class 全部的 member function definition,有沒有辦法對於某個 sp
ecialized class 來說我只特化它的其中一個 function,而且要用 original definition?
由於我必須複製它原始整份的實作到特化的函式定義裡面,才會編譯成功。想請問各位板大
有沒有不用複製整份程式碼也能只特化其中一個函式的方法?穴穴大家。
餵入的資料(Input):
預期的正確結果(Expected Output):
錯誤結果(Wrong Output):
程式碼(Code):(請善用置底文網頁, 記得排版,禁止使用圖檔)
我現在程式碼有定義一個可以根據 Leaf type 去特化的一個二元樹模板
template <typename Leaf> struct AUTOQ::Util::BinaryTree
.h 檔有放 prototype, .cpp 檔有放 implementation
那我們都知道如果要針對某種 Leaf 例如 int 去特化這棵二元樹,那必須在所有 *.cpp
的末尾加上 template struct AUTOQ::Util::BinaryTree<int>; 這句話才能把所有函式
實作特化出來。
但現在問題是,我的模板有包含一個兩棵二元樹相加的函式,而這個在 Leaf 是 string
的時候是無法支援的,因此我只想實作例如 AUTOQ::Util::BinaryTree<string> print
函式,那現在的狀況就是:
(1) 單純在有實作 print 的 .cpp 底下補上
template <> void AUTOQ::Util::BinaryTree<string>::print();
這句話,此時 main 函式會通報找不到這個實作,而無法編譯成功。
(2) 我在這個有實作 print 的 .cpp 底下補上
template <> void AUTOQ::Util::BinaryTree<string>::print() {
// 複製原本模板裡面的程式碼
}
這個新的實作,main 函式就找得到了。
所以問題就是,如何採用類似 (1) 的手法,使得我不需要再複製一次程式碼,就能直接
使用模板的實作呢?
補充說明(Supplement):
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 111.83.75.207 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1676046415.A.B53.html
→
02/11 00:27,
1年前
, 1F
02/11 00:27, 1F
推 LPH66: 繼承該特定 specialization 並 override 掉你要特化的函數 02/11 02:58
→
02/11 02:59,
1年前
, 2F
02/11 02:59, 2F
→
02/11 03:00,
1年前
, 3F
02/11 03:00, 3F
→
02/11 03:00,
1年前
, 4F
02/11 03:00, 4F
→
02/11 03:02,
1年前
, 5F
02/11 03:02, 5F
→ jack7775kimo: CRTP? 02/11 07:55
→
02/11 11:51,
1年前
, 6F
02/11 11:51, 6F
→
02/11 11:51,
1年前
, 7F
02/11 11:51, 7F
→ nh60211as: 把實作放在header 02/11 12:04
→
02/11 12:07,
1年前
, 8F
02/11 12:07, 8F
→
02/11 12:07,
1年前
, 9F
02/11 12:07, 9F
→
02/11 12:07,
1年前
, 10F
02/11 12:07, 10F
推 Fenikso: 能動header的話就用concept或enable_if處理吧 02/11 13:57
→
02/11 13:57,
1年前
, 11F
02/11 13:57, 11F
推
02/11 14:18,
1年前
, 12F
02/11 14:18, 12F
→
02/11 14:19,
1年前
, 13F
02/11 14:19, 13F
→
02/11 14:19,
1年前
, 14F
02/11 14:19, 14F
→
02/11 14:19,
1年前
, 15F
02/11 14:19, 15F
→
02/11 14:19,
1年前
, 16F
02/11 14:19, 16F
→
02/11 14:20,
1年前
, 17F
02/11 14:20, 17F
→
02/11 14:20,
1年前
, 18F
02/11 14:20, 18F
→
02/11 14:21,
1年前
, 19F
02/11 14:21, 19F
→
02/11 14:25,
1年前
, 20F
02/11 14:25, 20F
→
02/11 14:26,
1年前
, 21F
02/11 14:26, 21F
→
02/11 14:26,
1年前
, 22F
02/11 14:26, 22F
→
02/11 14:26,
1年前
, 23F
02/11 14:26, 23F
→
02/11 14:27,
1年前
, 24F
02/11 14:27, 24F
→
02/11 14:28,
1年前
, 25F
02/11 14:28, 25F
推 wulouise: 為甚麼你要寫在source file內感覺才是癥結點 02/12 00:17
→
02/12 00:36,
1年前
, 26F
02/12 00:36, 26F
推 closer76: 其實你去看大部分使用template 的函式庫,都是直接把實 02/12 09:03
→
02/12 09:03,
1年前
, 27F
02/12 09:03, 27F
→
02/12 09:03,
1年前
, 28F
02/12 09:03, 28F
→
02/12 09:15,
1年前
, 29F
02/12 09:15, 29F
→
02/12 09:15,
1年前
, 30F
02/12 09:15, 30F
→
02/12 09:15,
1年前
, 31F
02/12 09:15, 31F
→
02/12 09:15,
1年前
, 32F
02/12 09:15, 32F
→
02/12 09:15,
1年前
, 33F
02/12 09:15, 33F
→
02/12 09:49,
1年前
, 34F
02/12 09:49, 34F
→
02/12 09:49,
1年前
, 35F
02/12 09:49, 35F
推
02/12 13:11,
1年前
, 36F
02/12 13:11, 36F
→
02/12 13:11,
1年前
, 37F
02/12 13:11, 37F
推
02/12 13:19,
1年前
, 38F
02/12 13:19, 38F
→
02/12 13:19,
1年前
, 39F
02/12 13:19, 39F
→
02/12 13:20,
1年前
, 40F
02/12 13:20, 40F
→
02/12 13:21,
1年前
, 41F
02/12 13:21, 41F
→ firejox: 有external template 可以避免重覆生成啊 02/12 13:28
@ 以上紅底標記7位,每人1000P(稅前)發送完成! by AutoGiveP 2.12
我想結案了,參考完 https://stackoverflow.com/q/495021/11550178 這篇文章之後,
核心觀念大概就是,template definition 和一般的 class definition 有所不同,
一般的 class 可以分成 .h 和 .cpp 是因為具體的定義可以直接生成 .obj 檔案;然而
template definition 在參數未給定之前是無法生成具體的 .obj 的,必須等到參數給定
之後才行,因此即使當下 .cpp 可以 #include .h 檔,但是在還不確定要針對哪些參數
類別去做實體化的理由之下,也無用武之地。
如果直接把 template 實作在 .h 檔,那其他人 #include 這個 .h 檔之後就可以直接
看到實作,那當他想要使用實體化過後的 class 的時候就可以直接實體化。如果維持 .h
和 .cpp 分離,那唯一的手法就是在該 .cpp 底下加上 template struct Class<int>;
這句話以實作出「此 .cpp 所定義的」每個 member function,副作用就是整個 project
就只能使用 Class<int>,不能使用其他的 Class<T>,只要是某個 T 想用到 A.cpp 實作
的 member function,就必須在 A.cpp 底下補上 template struct Class<T>,同時也會
強迫 A.cpp 的其他 member function 也順勢實體化。
由於我的 .cpp 還有他人協作必須 #include 其他的 header file,無法任意搬家進 .h
檔裡面,所以最後採取的作法就是把不會受到限制的函式實作再移到另外一個 .cpp 檔,
例如 A.cpp (含 print 實作) 末尾加上
template struct AUTOQ::Util::BinaryTree<int>;
template struct AUTOQ::Util::BinaryTree<string>;
而 B.cpp (含 add 實作) 末尾只加上
template struct AUTOQ::Util::BinaryTree<int>;
如此一來問題就解決了,我不需要在特化 BinaryTree<string> 的時候再給出另一份新的
實作,可以直接使用原本的實作即可。
我大概猜得到原問題 (1) 的方法如果改加在 .h 檔應該會編譯成功,但是仍然不知為何
寫在 .cpp 無法有相同效果,是因為編譯器不支援部分實現嗎?只是這樣也不合理,那我
後來分成 A.cpp 和 B.cpp 的解法,不也是部分實現嗎?
註一:在我的中文用語認知內實現和特化有所不同,特化是指對於特定的參數提供另一種
函式的實作。
註二:@Fenikso 大大的解法我有試跑過,但它好像還是擋不住類似
template struct Foo<int>;
template struct Foo<std::string>;
加在 main 前面的實現,還是會報 error if Foo contains some function that cannot
be instantiated with std::string. 但是如果不加那兩行的話,也就不需要 requires
了。不知道如果要堅持這解法的話有沒有改進方案。
目前總共有 7 位鄉民留言,考量到個人財力,我想播 $7000 給各位鄉親,一人一千,
穴穴各位!
→
02/12 23:52,
1年前
, 42F
02/12 23:52, 42F
→
02/13 19:52,
1年前
, 43F
02/13 19:52, 43F
→
02/13 19:52,
1年前
, 44F
02/13 19:52, 44F
→
02/13 19:52,
1年前
, 45F
02/13 19:52, 45F
→
02/13 19:52,
1年前
, 46F
02/13 19:52, 46F
→
02/13 19:52,
1年前
, 47F
02/13 19:52, 47F
→
02/13 19:52,
1年前
, 48F
02/13 19:52, 48F
推
02/14 14:21,
1年前
, 49F
02/14 14:21, 49F
→
02/14 14:24,
1年前
, 50F
02/14 14:24, 50F
→
02/14 14:24,
1年前
, 51F
02/14 14:24, 51F
→
02/14 19:01,
1年前
, 52F
02/14 19:01, 52F
→
02/14 19:01,
1年前
, 53F
02/14 19:01, 53F
→
02/14 19:51,
1年前
, 54F
02/14 19:51, 54F
→
02/14 19:51,
1年前
, 55F
02/14 19:51, 55F
→
02/14 19:51,
1年前
, 56F
02/14 19:51, 56F
推
02/14 21:09,
1年前
, 57F
02/14 21:09, 57F
→ Fenikso: 是在 compile time 檢查 type T 有沒有支援這些操作 02/14 21:09
@ 以上紅底標記1位,每人1000P(稅前)發送完成! by AutoGiveP 2.12
※ 編輯: alan23273850 (111.82.62.46 臺灣), 02/14/2023 21:41:22
C_and_CPP 近期熱門文章
PTT數位生活區 即時熱門文章