模板化链接不适用于 -O2,但适用于 -O0
Templated linkage does not work on -O2, but does on -O0
我写了一个用cmake绑定的C++程序
并在 Debian 机器上运行。我很高兴地说所有已知的主要错误都是
已更正,我准备好从
开始
add_definitions(-Wall)
set(CMAKE_BUILD_TYPE Debug)
add_definitions("-O0 -std=c++0x")
一直到
add_definitions("-O2 -std=c++0x")
我就是这样做的,突然间我的项目中出现了一个模板化的 class
(天真地在某些 header 文件中声明并为所有 use-cases 定义
在一些单独的 .cpp 中)因 "undefined" 错误负载而中断
联动中
在这个论坛上进行的一些研究产生了如下主题:
Why can templates only be implemented in the header file?
我相信我看到 Luc 在他著名的回答中正在推动什么
在:编译器
实际上 'writes code' 每个需要的模板版本 class
(即 T=int、T=float、T=what_ever_else),为此需要
访问实际实现。
很公平。但是这里完全让我感到困惑的是:这显然
只有在尝试优化编译时才是一个问题。使用
“-O0”一切正常。怎么可能?
附录
1.)关于重复嫌疑人:这里的问题不是我做了什么
那是错的。我的罪过很明显:我定义了遥不可及的模板函数
header 文件,由于所述原因显然不允许
post 上面和里面我已经引用了。
鉴于上述引用的真实性 posting 很明显我的程序无法编译。我不明白的是:为什么 does it compile with -O0.
2.) 没有要求一些明确的错误。我最后一次尝试使用 -O2 的结尾仍在我的终端缓冲区中(抱歉,编译大约需要一个小时,因此不容易重现)。但实际上它在链接期间中断了。这是我仍然可以将鼠标指针放在上面的内容:
/home/kochmn/projects/free_sentinel_gl/sentinel/src/game/game.cpp:432: undefined reference to `game::Board<game::Figure>::get(QPoint)'
libqt.a(game.cpp.o): In function `game::Game::hyperspace_jump()':
/home/kochmn/projects/free_sentinel_gl/sentinel/src/game/game.cpp:950: undefined reference to `game::Board<game::Square>::get(QPoint)'
[... many more like that all concerned about the templated class "Board"
which is declared in landscape.h, defined in landscape.cpp and
used pretty much everywhere else ... ]
collect2: error: ld returned 1 exit status
CMakeFiles/sentinel.dir/build.make:548: recipe for target 'sentinel' failed
make[2]: *** [sentinel] Error 1
CMakeFiles/Makefile2:127: recipe for target 'CMakeFiles/sentinel.dir/all' failed
make[1]: *** [CMakeFiles/sentinel.dir/all] Error 2
Makefile:76: recipe for target 'all' failed
make: *** [all] Error 2
3.) 关于评论问题 "How are the use-cases defined?":让我们利用这个在 GitHub.
上的事实
所有 use-cases 都在此处定义:https://github.com/kochsoft/free_sentinel_gl/blob/master/sentinel/src/game/landscape.cpp#L507 从第 507 行开始。
header 在这里:https://github.com/kochsoft/free_sentinel_gl/blob/master/sentinel/src/include/landscape.h#L363 从第 363 行开始的相关段落。
我的问题已解决,dyp 最接近 his/her 评论。神奇的词是 "explicit template instanciation",可以在这里找到:http://www.cplusplus.com/forum/articles/14272/
我没有用定义弄乱我的 header 文件。我也没有将 #include "some.cpp" 之类的代码添加到 header 中,在我看来它们是一样的。相反,我添加了行
template class Board<Figure>;
template class Board<Square>;
正好在 landscape.cpp 中的定义下,并且能够使用 -O2 进行编译。
根据 Why can templates only be implemented in the header file?,我只能在我的板上使用数字和正方形(这很适合我)。
至于 -O0 为何起作用:正如 dyp 在上面的评论中所述,优化编译器可能删除了一些在 -O0 下用于模板实例化的代码片段。大概……我还不敢说完全看懂了。
@dyp:你为什么不post对那个问题的全面回答来证实你之前的评论?
我写了一个用cmake绑定的C++程序 并在 Debian 机器上运行。我很高兴地说所有已知的主要错误都是 已更正,我准备好从
开始add_definitions(-Wall)
set(CMAKE_BUILD_TYPE Debug)
add_definitions("-O0 -std=c++0x")
一直到
add_definitions("-O2 -std=c++0x")
我就是这样做的,突然间我的项目中出现了一个模板化的 class (天真地在某些 header 文件中声明并为所有 use-cases 定义 在一些单独的 .cpp 中)因 "undefined" 错误负载而中断 联动中
在这个论坛上进行的一些研究产生了如下主题: Why can templates only be implemented in the header file? 我相信我看到 Luc 在他著名的回答中正在推动什么 在:编译器 实际上 'writes code' 每个需要的模板版本 class (即 T=int、T=float、T=what_ever_else),为此需要 访问实际实现。
很公平。但是这里完全让我感到困惑的是:这显然 只有在尝试优化编译时才是一个问题。使用 “-O0”一切正常。怎么可能?
附录
1.)关于重复嫌疑人:这里的问题不是我做了什么 那是错的。我的罪过很明显:我定义了遥不可及的模板函数 header 文件,由于所述原因显然不允许 post 上面和里面我已经引用了。
鉴于上述引用的真实性 posting 很明显我的程序无法编译。我不明白的是:为什么 does it compile with -O0.
2.) 没有要求一些明确的错误。我最后一次尝试使用 -O2 的结尾仍在我的终端缓冲区中(抱歉,编译大约需要一个小时,因此不容易重现)。但实际上它在链接期间中断了。这是我仍然可以将鼠标指针放在上面的内容:
/home/kochmn/projects/free_sentinel_gl/sentinel/src/game/game.cpp:432: undefined reference to `game::Board<game::Figure>::get(QPoint)'
libqt.a(game.cpp.o): In function `game::Game::hyperspace_jump()':
/home/kochmn/projects/free_sentinel_gl/sentinel/src/game/game.cpp:950: undefined reference to `game::Board<game::Square>::get(QPoint)'
[... many more like that all concerned about the templated class "Board"
which is declared in landscape.h, defined in landscape.cpp and
used pretty much everywhere else ... ]
collect2: error: ld returned 1 exit status
CMakeFiles/sentinel.dir/build.make:548: recipe for target 'sentinel' failed
make[2]: *** [sentinel] Error 1
CMakeFiles/Makefile2:127: recipe for target 'CMakeFiles/sentinel.dir/all' failed
make[1]: *** [CMakeFiles/sentinel.dir/all] Error 2
Makefile:76: recipe for target 'all' failed
make: *** [all] Error 2
3.) 关于评论问题 "How are the use-cases defined?":让我们利用这个在 GitHub.
上的事实所有 use-cases 都在此处定义:https://github.com/kochsoft/free_sentinel_gl/blob/master/sentinel/src/game/landscape.cpp#L507 从第 507 行开始。
header 在这里:https://github.com/kochsoft/free_sentinel_gl/blob/master/sentinel/src/include/landscape.h#L363 从第 363 行开始的相关段落。
我的问题已解决,dyp 最接近 his/her 评论。神奇的词是 "explicit template instanciation",可以在这里找到:http://www.cplusplus.com/forum/articles/14272/
我没有用定义弄乱我的 header 文件。我也没有将 #include "some.cpp" 之类的代码添加到 header 中,在我看来它们是一样的。相反,我添加了行
template class Board<Figure>;
template class Board<Square>;
正好在 landscape.cpp 中的定义下,并且能够使用 -O2 进行编译。
根据 Why can templates only be implemented in the header file?,我只能在我的板上使用数字和正方形(这很适合我)。
至于 -O0 为何起作用:正如 dyp 在上面的评论中所述,优化编译器可能删除了一些在 -O0 下用于模板实例化的代码片段。大概……我还不敢说完全看懂了。
@dyp:你为什么不post对那个问题的全面回答来证实你之前的评论?