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

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

4

2 に答える 2

2

コンパイラの複雑さはわかりませんが、とにかく標準に違反しています:

14.7.3 明示的な特殊化:

6 テンプレート、メンバーテンプレート、またはクラステンプレートのメンバーが明示的に特殊化されている場合、その特殊化は、そのような使用が行われるすべての翻訳単位で、暗黙的なインスタンス化を引き起こす特殊化の最初の使用の前に宣言されなければならない発生します。診断は必要ありません。

したがって、プログラムの形式が正しくありません。

于 2013-07-18T10:13:11.063 に答える