C_and_CPP 板


LINE

开发平台(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): --
QR Code



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 111.83.75.207 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1676046415.A.B53.html
1F:→ alan23273850: 程式码我明天再补 02/11 00:27
LPH66: 继承该特定 specialization 并 override 掉你要特化的函数 02/11 02:58
2F:→ LPH66: 这样可以吗? 02/11 02:59
3F:→ LPH66: 噢等等, 如果该函数没有 virtual 那 override 抓不到 02/11 03:00
4F:→ LPH66: 原程式码呼叫被盖掉的函数的状况 02/11 03:00
5F:→ LPH66: 不过如果你动得到模版原始码的话, 加个 virtual 应该就行了 02/11 03:02
jack7775kimo: CRTP? 02/11 07:55
6F:→ alan23273850: 我补上程式码了,这个问题对我来说很重要,如果获得 02/11 11:51
7F:→ alan23273850: 解答的话我将奉送大量批币! 02/11 11:51
nh60211as: 把实作放在header 02/11 12:04
8F:→ alan23273850: @jack7775kimo 大那个关键字我刚刚查了一下好像很酷 02/11 12:07
9F:→ alan23273850: 但不确定能不能用在这里 02/11 12:07
10F:→ alan23273850: @nh60211as 大的解法我可能需要更具体的理由 02/11 12:07
Fenikso: 能动header的话就用concept或enable_if处理吧 02/11 13:57
11F:→ Fenikso: https://godbolt.org/z/36E585xr8 02/11 13:57
12F:推 LPH66: template 其实会常见把实作写在 header 里的做法 02/11 14:18
13F:→ LPH66: 理由是模版实现只在给定所有模版参数之後 02/11 14:19
14F:→ alan23273850: 我理解 @Fenikso 大大正面表列的作法,但是这样会有 02/11 14:19
15F:→ LPH66: 除非像你这样特别去引用一个模版把它特化出来 02/11 14:19
16F:→ alan23273850: 一堆 function 要加上 requires 很不方便,更重要的 02/11 14:19
17F:→ LPH66: 不然你是无法对别的 TU 里引用的模版去产生程式码的 02/11 14:20
18F:→ alan23273850: 是,我不知道为何内文 (1) 的作法编译器会不通过。 02/11 14:20
19F:→ LPH66: 把实作写在标头就把很多决定模版的地方延後到使用处生成 02/11 14:21
20F:→ alan23273850: 哦哦哦 但是我好像渐渐对 @Fenikso 大大的答案有点 02/11 14:25
21F:→ alan23273850: 感觉了,只要实作的地方先加注 prerequisites 确保 02/11 14:26
22F:→ alan23273850: 实作完毕,才开始实现我这个函式,好像就能避免掉我 02/11 14:26
23F:→ alan23273850: 那个问题,我礼拜一有空会试试看,如果 OK 的话就 02/11 14:26
24F:→ alan23273850: 奉送 @Fenikso 一个大礼! 02/11 14:27
25F:→ alan23273850: 也谢谢 @LPH66 大大的解说,两个我都会试试看。 02/11 14:28
wulouise: 为甚麽你要写在source file内感觉才是症结点 02/12 00:17
26F:→ alan23273850: 一般不是都鼓励分成两个档案吗?不然理由是什麽呢 02/12 00:36
closer76: 其实你去看大部分使用template 的函式库,都是直接把实 02/12 09:03
27F:→ closer76: 作写在 header files 里的。原因是大部分的编译器都不支 02/12 09:03
28F:→ closer76: 援有 template 的类别、函式内容另外定义。 02/12 09:03
29F:→ closer76: 其实你可以用编译器的角度想想:template 其实就是编译 02/12 09:15
30F:→ closer76: 器要帮你特化,所以编译器需要知道 template 的原始码。 02/12 09:15
31F:→ closer76: 而 C++ 又没有强制要求实作和宣告的档名一定要有关连, 02/12 09:15
32F:→ closer76: 那麽编译器就得搜寻整个专案,才能找到定义的原始码。增 02/12 09:15
33F:→ closer76: 加编译器实作成本。那为何不乾脆要求放在一起呢? 02/12 09:15
34F:→ alan23273850: @closer76 如果不是 template 的话不也是要搜寻整 02/12 09:49
35F:→ alan23273850: 个专案吗? 02/12 09:49
36F:推 closer76: 没有 template 的话,至少可以先编成 obj,symbol table 02/12 13:11
37F:→ closer76: 对 linker 来说也是比较容易处理的资料 02/12 13:11
38F:推 closer76: C++ 原本是用 export 关键字来做这件事的,但因为太难做 02/12 13:19
39F:→ closer76: ,所以後来被移出标准了。可以参考这里: 02/12 13:19
40F:→ closer76: https://stackoverflow.com/questions/5416872/ 02/12 13:20
41F:→ closer76: 里面有提到 C++20 有 module 功能,但我没研究过 02/12 13:21
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 给各位乡亲,一人一千, 穴穴各位!
42F:→ Fenikso: 不知道你怎麽改的 报error的写法丢上来看看? 02/12 23:52
43F:→ alan23273850: 感谢楼上大大持续追踪,请先切换到 https://github 02/13 19:52
44F:→ alan23273850: .com/alan23273850/AutoQ/commit/8ebd44aeeaa42a2e 02/13 19:52
45F:→ alan23273850: 68ee80779147b84b17301e42 这个记录点,按照 readm 02/13 19:52
46F:→ alan23273850: e 去编译会发现可以过,接着把此变化内的 aut_oper 02/13 19:52
47F:→ alan23273850: ation.cc 最底部 4 个 Automata<Predicate> 实作的 02/13 19:52
48F:→ alan23273850: 函式直接改成分号结尾,然後就会发现不能编译了 :( 02/13 19:52
49F:推 Fenikso: 啊因为你不能instantiate那些不该出现的function 02/14 14:21
50F:→ Fenikso: https://bit.ly/3Xt3iN1 把所有不该给Predicate用的东西 02/14 14:24
51F:→ Fenikso: 加上requires这样就行了 02/14 14:24
52F:→ alan23273850: 感谢 @Fenikso 大大帮我改程式码,我有空再消化消化 02/14 19:01
53F:→ alan23273850: 看懂再加码 1000P 02/14 19:01
54F:→ alan23273850: 所以那个 requires 里面的三行是故意去呼叫看看那 02/14 19:51
55F:→ alan23273850: 三个函式有没有支援吗?可是看起来好像 runtime 会 02/14 19:51
56F:→ alan23273850: 实际去执行的程式码。 02/14 19:51
57F:推 Fenikso: 对看起来很像 runtime 但不是 XD 02/14 21:09
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







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