2013-06-19 9 views
5

私はテンプレートを特化し、MSVCコンパイラとMinGW/GCCの間に違ったビアビールを見つけました。ヘッダーファイルは次のとおりです。テンプレートの特化 - MSVCとGCC/MinGWの動作が異なる

// MyClass.h 
#ifndef MYCLASS_HEADER 
#define MYCLASS_HEADER 

template<typename T> 
class MyClass { 
public: 
    virtual void doSomething() { 
     // some code 
    } 
}; 

// specialization prototype here 

#endif 

ここでは違いがあります。複数の定義を避けるために、私はヘッダーファイルのプロトタイプのみを専門にしました。実装はcppファイルにあります。専門性が問題です。と

// MyClass.cpp 
#include "MyClass.h" 

template<> void MyClass<int>::doSomething() { 
    // some code 
} 

extern template void MyClass<int>::doSomething(); // MSVC version 

CPPファイル内の実装はどちらも同じです

:これだけは

template<> void MyClass<int>::doSomething(); // GCC version 

そしてMSVC:GCC/MinGWのコンパイラはこれだけを受け入れGCCプロトタイプMSVCコンパイラは "未解決の外部シンボル"エラーをスローし、MSVCバージョンのGCCは "インスタンス化後の...の特殊化"をスローします。

瞬間、私は回避策があります:ヘッダファイルに

#ifdef _MSC_VER 
extern template 
#else 
template<> 
#endif 
void MyClass<int>::doSomething(); 

を。それは動作しますが、私はそれが好きではありません。コンパイラ固有のスイッチを避ける方法はありますか?

+0

使用しているMSVCとGCCのバージョンは何ですか? – Gonmator

+0

MSVC 2010 SP1とGCC 4.7 – WoJo

答えて

5

:。

template<> void MyClass<int>::doSomething(); // GCC version 

extern template void MyClass<int>::doSomething(); // MSVC version 

最初のものは、明示的な専門を宣言し、二つ目は、明示的なインスタンス化を宣言

MSVCコンパイラがMSVCコンパイラで「未解決の外部シンボル」エラーをスローすると、MSVCバージョンのGCCが「インスタンス化後の...の特殊化」をスローします。

GCCエラーは、明示的な特殊化の宣言よりもファイル内で暗黙の具体化がMyClass<int>::doSomething()であったことを示しています。それはあなたのコードのバグです。明示的な特殊化は、暗黙的なインスタンス化を使用する前に宣言する必要があります。そうしないと、暗黙的なインスタンス化では、特殊化ではなく主テンプレート定義が使用されます。特殊化は、通常、プライマリテンプレートの定義の直後に、MyClass<int>のインスタンス化より前に宣言することによって使用前に宣言されます。

なぜMSVCエラーが発生するのか分かりませんが、MyClass.cppにリンクしていないかのように聞こえます。それはそれではない場合は、そのファイル内に放出されるシンボルを強制的にMyClass.cppに明示的なインスタンスの定義を追加してみてください:

template void MyClass<int>::doSomething(); // N.B. no "extern" on definition 

あなたは両方専門とインスタンス化を宣言したが、それらが宣言されている確保しようとしたことがありの前に暗黙的なインスタンス化はありますか?これは有効なC++でなければなりません。

#ifndef MYCLASS_H 
#define MYCLASS_H 
template<typename T> 
class MyClass { 
public: 
    virtual void doSomething() { 
     // some code 
    } 
}; 
// declare explicit specialization 
template<> void MyClass<int>::doSomething(); 
// declare explicit instantiation 
extern template void MyClass<int>::doSomething(); 
#endif 

// MyClass.cpp 
#include "MyClass.h" 

// define explicit specialization 
template<> void MyClass<int>::doSomething() { 
    // some code 
} 
// define explicit instantiation 
template void MyClass<int>::doSomething(); 

あなたは両方のコンパイラでその仕事をすることができない場合は別の方法として、あなたはまた、複数の定義のエラーを避けることになる、ヘッダー内の特殊なメンバ関数の定義を入れてinlineそれを宣言することができます。

+0

' inline'が問題を解決しました。今、ヘッダファイルに定義があります: 'template <> inline MyClass :: doSomething(){/ * code * /}'は両方のコンパイラで動作します。ありがとう – WoJo

0

それは標準ではexternが正しいことを言うように、いくつかの実装のバグかもしれないです:14.7.2明示的なインスタンスから

抜粋:

「明示的なインスタンスの構文は次のとおりです。
にexternテンプレート宣言

OPTの2つの形式があります。明示的なインスタンス化:明示的なインスタンス化の定義と明示的なインスタンス化の宣言。明示的なインスタンス宣言は、にexternキーワードで始まり、「これらは同じものではありません

+0

Standardでは、クラステンプレートの[...] - メンバ関数の明示的な特殊化は、 'template <>'によって導入された宣言で宣言できます_ "にもかかわらず、コンパイラがうまく動作するかどうかを知ることは非常に面白いですが、それは質問に答えません。 – Gonmator

+0

次に、私の答えはいいえ、コンパイラの適合性が向上するまで、おそらく最良の方法です。 – TractorPulledPork

+0

'extern'は正しい**明示的なインスタンス化を宣言したい場合** ... OPが何をしたいのかは分かりません –

関連する問題