2009-04-20 18 views
8

私は、テンプレートの特殊化を使用して異なる方法でハンドルのテンプレート関数を実装しようとしています。静的メンバー関数のテンプレートの特殊化。の仕方?

次のコードは、GCCで私に「非名前空間スコープでの明示的な特化」を与える:

template <typename T> 
static T safeGuiCall(boost::function<T()> _f) 
{ 
    if (_f.empty()) 
     throw GuiException("Function pointer empty"); 
    { 
     ThreadGuard g; 
     T ret = _f(); 
     return ret; 
    } 
} 

// template specialization for functions wit no return value 
template <> 
static void safeGuiCall<void>(boost::function<void()> _f) 
{ 
    if (_f.empty()) 
     throw GuiException("Function pointer empty"); 
    { 
     ThreadGuard g; 
     _f(); 
    } 
} 

私はクラスの外に移動してみました(クラスはテンプレートではありません)と名前空間にしましたが、 「明示的な特殊化にはストレージクラスを持たない」というエラーが表示されます。私はこれについて多くの議論を読んだことがありますが、人々は機能テンプレートをどのように特化するかについて合意していないようです。何か案は?

答えて

12

あなたがテンプレート法を専門とするとき、あなたはクラスの括弧の外に行う必要があります。

template <typename X> struct Test {}; // to simulate type dependency 

struct X // class declaration: only generic 
{ 
    template <typename T> 
    static void f(Test<T>); 
}; 

// template definition: 
template <typename T> 
void X::f(Test<T>) { 
    std::cout << "generic" << std::endl; 
} 
template <> 
inline void X::f<void>(Test<void>) { 
    std::cout << "specific" << std::endl; 
} 

int main() 
{ 
    Test<int> ti; 
    Test<void> tv; 
    X::f(ti); // prints 'generic' 
    X::f(tv); // prints 'specific' 
} 

あなたはクラスの外でそれを取るとき、あなたは削除する必要があります'static'キーワード。クラス外の静的キーワードは、おそらくあなたが望むものとは異なる特定の意味を持ちます。

template <typename X> struct Test {}; // to simulate type dependency 

template <typename T> 
void f(Test<T>) { 
    std::cout << "generic" << std::endl; 
} 
template <> 
void f<void>(Test<void>) { 
    std::cout << "specific" << std::endl; 
} 

int main() 
{ 
    Test<int> ti; 
    Test<void> tv; 
    f(ti); // prints 'generic' 
    f(tv); // prints 'specific' 
} 
+0

hm私は今同じことを試みましたが、それを.hppファイルに入れて、それを含めようとしました... "vodi Xの複数定義:ff (Test )というエラーが表示されます。違いがありますか? – Rolle

+1

コンパイラまたはリンカのエラーですか?コンパイラエラーの場合は、おそらくテンプレートヘッダーを複数回インクルードしていて、ヘッダーガードがなくなっていることを意味します。つまり、コンパイラは実装の定義を2つ(正確には正確です)表示します。 –

+0

最初のケースでインラインを追加するのはなぜですか?そうでない場合は、私はコンパイルのエラーを取得しています。 – sop

3

あなたはそのクラスの外のメンバ関数を定義したいと同じように、明示的な特殊化を宣言することができます。

class A 
{ 
public: 
    template <typename T> 
    static void foo() {} 
}; 

template <> 
void A::foo<void>() 
{ 
} 
+0

お返事ありがとうございます。私の場合、クラス内にいるかどうかは問題ではありません。私はそれをどちらの方法でも動作させることはできません。私の構文が間違っているのか、私が提供したコードに何かがありますか? – Rolle

+0

要点は、修飾された関数宣言子を使って名前空間の関数を明示的に特殊化することです。 C++では 'static'キーワードを再度追加することはできません。上の例では、静的メンバーを明示的に特殊化する方法を示しています。 –

2

あなたの問題は、ブースト::機能であるように思われる - 以下の専門は機能:

+0

申し訳ありませんが、これを試しても動作しません。 gccでコンパイルしましたか?私はVSの下で動作すると思います... – Rolle

+0

これはg ++バージョン3.4.5です –

+0

それはすべて削除する必要があり、それらはすべて削除してください、comauとコンパイルします、回答を更新します –

4

それは直接あなたの質問への答えではないのですが、あなたはこの

template <typename T> 
static T safeGuiCall(boost::function<T()> _f) 
{ 
     if (_f.empty()) 
       throw GuiException("Function pointer empty"); 
     { 
       ThreadGuard g; 
       return _f(); 
     } 
} 
を書くことができます

_f()が 'void'を返す場合でも動作するはずです

編集:もっと一般的なケースでは、私は特殊化の代わりに関数のオーバーロードを優先すべきだと思います。ここでは、このための良い説明は次のとおりです。http://www.gotw.ca/publications/mill17.htm

+1

はいとても良い点 –

+0

それがうまく動作しないと確信しています。 Tはどこにも定義されていませんか? – Rolle

+0

@Rolle申し訳ありません "テンプレート"はコピー/ペーストまで存続しませんでした。 – Rexxar

1

私は同様の問題がありました。元の投稿を見ると、最初の静的なままにしていましたが、2番目の静的なものを取り除き、両方のエラーがなくなりました。

関連する問題