以下构建设置在使用GCC(4.6.3)的Linux上运行正常,但在使用GCC(4.7.2)的MinGW中运行不正常。
$ cat Makefile
all:
g++ -c foo.cpp
g++ -c bar.cpp
g++ bar.o foo.o -o bar
$ cat foo.h
#ifndef FOO_H
#define FOO_H
#include <iostream>
template <typename T>
void foo(T x) {
std::cout << "Hello World!" << std::endl;
}
#endif
$ cat foo.cpp
#include "foo.h"
template <>
void foo(int x) {
std::cout << "Hello Int!" << std::endl;
}
$ cat bar.cpp
#include "foo.h"
int main() {
foo <int> (1);
}
在Linux上,我们有:
$ make
g++ -c foo.cpp
g++ -c bar.cpp
g++ bar.o foo.o -o bar
$ ./bar
Hello Int!
这是我的期望。在Windows上,我们有
$ make
g++ -c foo.cpp
g++ -c bar.cpp
g++ bar.o foo.o -o bar
foo.o:foo.cpp:(.text+0x0): multiple definition of `void foo<int>(int)'
bar.o:bar.cpp:(.text$_Z3fooIiEvT_[__Z3fooIiEvT_]+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
make: *** [all] Error 1
我怀疑这与弱符号有关。意思是,在Linux上我们有foo.o
00000000 T _Z3fooIiEvT_
并在bar.o
00000000 W _Z3fooIiEvT_
而在Windows上我们在foo.o
中有00000000 T __Z3fooIiEvT_
并在bar.o
00000000 T __Z3fooIiEvT_
因此,没有弱的符号可以覆盖。
解决此问题的最佳方法是什么?在实际情况中,我有一个带有许多模板定义的头文件foo.h。其中一些,我专注,我把这些定义放在foo.cpp中,后来编译成一个库。然后,我将标题和库提供给用户。如果可能的话,我总是想在foo库中使用特化。如果不存在特化,我想在foo标题中使用模板定义。
修改
foo.h的以下修改似乎解决了问题
$ cat foo.h
#ifndef FOO_H
#define FOO_H
#include <iostream>
template <typename T>
void foo(T x) {
std::cout << "Hello World!" << std::endl;
}
template <>
void foo(int x);
#endif
基本上,foo的int版本的原型需要在头文件中。这符合BoBTFish的说明,该标准要求“专业化应在首次使用前申报”。无论如何,这是设置专业化库的最佳方法吗?
答案 0 :(得分:2)
不知道编译器的复杂性,但你仍然违反了标准:
14.7.3明确的专业化:
6如果是模板,成员模板或类模板的成员 明确专业化,然后声明专业化 在第一次使用该特化之前会导致一个 隐式实例化发生在每个翻译单元中 发生了这种用途;无需诊断。
所以你的程序结构不合理。
答案 1 :(得分:1)
您可以安装(在Windows和Linux上)最近的GCC(今天是4.8.1)并使用C ++ 11的extern template功能。