Re: [问题] template class 内 static 初始问题

楼主: sarafciel (Cattuz)   2018-06-23 00:17:33
※ 引述《lovejomi (JOMI)》之铭言:
: https://wandbox.org/permlink/skxmougiYnaw1f1a
: 一开始遭遇到这个compile warning
: warning: instantiation of variable 'Foo<int>::bar' required here, but no defin
: ition is available [-Wundefined-var-template]
: 其实我不太知道他为什么会warning
: 我确实有define在test.cpp这个translation unit
: 不懂的是 他感觉找不到定义 却让我pass, run time 也有拿到对的数值.
: 而g++不会有warning
: 1. 到这边我还是不知道到底哪里写的不够正确?
: 然而我试着解决这warning
: 于是我把 上面的
: //b.
: // extern template class Foo<int>;
: 打开
: https://wandbox.org/permlink/j2ANWRBoeIZZJAHE
: link error
: undefined reference to `Foo<int>::Test()'
: 如果不呼叫 这个warning确实可以这样解决
: 但我必须呼叫这function
: 2. 为什么他这样会说undefined? .h里面明确有包含定义阿?
先厘清两件事:
1.你没给定型态的template它就不是明确定义,自然它也不会被编译。
2.template在两份不同的.cpp档里给定型态,会在编译时各自生成两份实作。
回到你的code上面,当你使用extern template的时候
代表你指定在编译时这份cpp档参考其他cpp或.o里的实作
而你在test.cpp里的实作只有对bar做模板特化,那么在编译时test.cpp只会有bar有定义
其他symbol它不会自动帮你生,所以你的主程式自然找不到test()的实作
如果是使用template class Foo<int>的情况
你这个时候就是让主程式生自己的实作了,而且因为它不是做特化而是直接给参
所以会整个class都生给你
: 然而
: //a.
: // template class Foo<int>;
: 打开后
: 3. 我认为我已经明确让他产生程式码了.... warning还是存在
: 回归1. 的问题 我到底少做了什么让clang这样出warning
残念的是我这边的clang还在3.8.1,好像跑不出这个warning(汗)
所以以下是我猜的,有错欢迎版上高手指正XD
上面说过template会在不同的cpp生成各自的实作
你在test.cpp做特化时bar是有defination的,所以会替bar在.data留一个位子
到编主程式的时候它又为主程式生一份Foo<int>的实作,
这边第二份实作的bar没有给值,所以它是declaration
可是你对bar的defination必须等到做link的时候才会看到
compile阶段编译器是看不到的,所以compiler丢这个警告给你
提醒你bar这个static variable还是undefined的状态
所以你link时有抓到它的symbol,应该就没事这样XD
: 4. 对于template class内 有static function or data
: 最正确的写法该怎么写.
: 网络上有查到
: 在test.h 直接写
: template<class T>
: int Foo<T>::bar = 初始直;
: test.cpp一样写
: template<>
: int Foo<int>::bar = 123;
: 但我实际上在专案遇到一个况状是
: 我某个cpp 写Foo<int>::bar 拿到的却是.h给的初始直(我认为是他初始化顺序优先于te
: st.cpp)
: 所以目前毫无办法处理这warning
template最正确的写法,就是通通给它塞在header里
如果你觉得header有够长,整个给你塞template塞得不要不要的
那就另外写个.tcc档,然后叫header把tcc include进来
要在.cpp用的时候就是只做给定型态的事,以你的例子来讲
template<class T>
int Foo<T>::bar = 0;
template<>
int Foo<int>::bar = 123;
这两个就别再外写cpp编译了,直接放在test.h里就好
不然就是再写个test.tcc,然后在test.h最后面加一行#include "test.tcc"
以我自己的经验,不管是boost还是标准库基本上都是按这个模式在写template
: 5. 这似乎没办法用static是internal linkage 来解释...让我整个无法通透理解
: 请教各位有什么方法处理这问题
: 谢谢
作者: lovejomi (JOMI)   2018-06-23 02:00:00
最后的说法 把Foo<int>::bar=123写在header,两个cpp include就redefine了耶
楼主: sarafciel (Cattuz)   2018-06-23 09:02:00
汗 我写一写忘记把test.cpp补回去编译orz不过这个可以拿弱符号解掉的样子int __attribute__((weak)) Foo<int>::bar =123;把那行特化换成这个

Links booklink

Contact Us: admin [ a t ] ucptt.com