次のビルド セットアップは、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
基本的に、int バージョンの foo のプロトタイプはヘッダーにある必要があります。これは、標準では「特殊化は最初の使用の前に宣言する必要がある」ことが要求されているという BoBTFish の注記と一致します。いずれにせよ、これは専門化ライブラリをセットアップする最良の方法ですか?