15

テンプレート クラスで (静的) メンバー関数/定数を特殊化すると、宣言がどこに行くべきかについて混乱します。

これは私が何をすべきかの例です -テンプレートの特殊化に関するIBMのリファレンスから直接引用しました:

===IBM メンバーのスペシャライゼーションの例===

template<class T> class X {
public:
   static T v;
   static void f(T);
};

template<class T> T X<T>::v = 0;
template<class T> void X<T>::f(T arg) { v = arg; }

template<> char* X<char*>::v = "Hello";
template<> void X<float>::f(float arg) { v = arg * 2; }

int main() {
   X<char*> a, b;
   X<float> c;
   c.f(10); // X<float>::v now set to 20
}

問題は、これをヘッダー/cpp ファイルに分割するにはどうすればよいかということです。一般的な実装は明らかにヘッダーにありますが、特殊化はどうでしょうか?

これは具体的であり、複数の定義につながるため、ヘッダー ファイルに入れることはできません。しかし、それが .cpp ファイルに入った場合、X::f() を呼び出すコードは特殊化を認識していますか、それともジェネリック X::f() に依存している可能性がありますか?

これまでのところ、.cpp のみに特殊化されており、ヘッダーには宣言がありません。コードのコンパイルや実行に問題はありません (gcc では、現時点ではバージョンを覚えていません)。特殊化を認識して、期待どおりに動作します。しかし、A)これが正しいかどうかはわかりません。何が正しいのか知りたいのですが、B)Doxygenのドキュメントが不安定で非常に誤解を招くようになっています(これについては後で質問します)。

私にとって最も自然に思えるのは、次のようなもので、ヘッダーで特殊化を宣言し、.cpp で定義することです。

===XClass.hpp===

#ifndef XCLASS_HPP
#define XCLASS_HPP

template<class T> class X {
public:
   static T v;
   static void f(T);
};

template<class T> T X<T>::v = 0;
template<class T> void X<T>::f(T arg) { v = arg; }

/* declaration of specialized functions */
template<> char* X<char*>::v;
template<> void X<float>::f(float arg);

#endif

===XClass.cpp===

#include <XClass.hpp>

/* concrete implementation of specialized functions */
template<> char* X<char*>::v = "Hello";
template<> void X<float>::f(float arg) { v = arg * 2; }

...しかし、これが正しいかどうかはわかりません。何か案は?

4

4 に答える 4

11

inline通常、dirkgently が言ったように、ヘッダーで特殊化を定義するだけです。

コンパイル時間やコードの肥大化が心配な場合は、別の翻訳単位で特殊化を定義できます。

// x.h:
template<class T> struct X {
    void f() {}
}

// declare specialization X<int>::f() to exist somewhere: 
template<> void X<int>::f();

// translation unit with definition for X<int>::f():
#include "x.h"
template<> void X<int>::f() {
    // ...
}

そうです、あなたのアプローチはうまく見えます。これは完全な特殊化でのみ行うことができることに注意してください。したがって、これを行うことは多くの場合非現実的です。

詳細については、例: Comeaus テンプレートの FAQを参照してください。

于 2010-03-23T12:46:57.417 に答える
4

それらをすべてhppファイルに入れます。特殊化と、クラス外で定義するものをすべて作成inlineします。これにより、複数の定義が処理されます。

于 2010-03-23T08:34:11.827 に答える
1

質問の 1 つに答えるには:is code which calls X::f() aware of the specialization, or might it rely on the generic X::f()?

コンパイラは、要件に一致する定義を検出すると、それを使用します。それ以外の場合は、通常の関数呼び出しが生成されます。

最初のコード スニペットでは、 の一般的な定義を提供するX<T>::f(T arg)ため、コンパイラはT以外のすべてに対してそれをインスタンス化しますfloat

ジェネリック定義を省略した場合、コンパイラは呼び出しを生成しX<double>::f(double)、リンカはリンカ エラーで終了する可能性のある定義を検索します。

要約すると、テンプレートとして複数の定義を取得できないため、すべてをヘッダーに含めることができます。宣言しかない場合は、リンカーが後で見つけられるように、別の場所に定義が必要になります。

于 2010-03-23T11:07:44.633 に答える