以下构建设置在使用 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 的注释相吻合,即标准要求“专业化应在首次使用之前声明”。无论如何,这是设置专业化库的最佳方式吗?