3

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

4

2 回答 2

2

不知道编译器的复杂性,但无论如何你都违反了标准:

14.7.3 显式专业化:

6 如果模板、成员模板或类模板的成员被显式特化,则该特化应在第一次使用该特化之前声明,该特化将导致发生隐式实例化,在每个翻译单元中使用该特化发生;不需要诊断。

所以你的程序格式不正确。

于 2013-07-18T10:13:11.063 回答
1

您可以安装(在 Windows 和 Linux 上)最新的 GCC(今天是 4.8.1)并使用 C++11 的extern 模板功能。

于 2013-07-18T10:10:55.797 回答