19

私のコードは複数の .dll ファイルにビルドされており、静的メンバー変数を持つテンプレート クラスがあります。

この静的メンバー変数の同じインスタンスをすべての dll で使用できるようにしたいのですが、うまくいきません。それぞれに異なるインスタンス (異なる値) が表示されます。

テンプレートを使用しない場合、問題はありません。ソース ファイルの 1 つで静的メンバーを初期化し、クラスで __declspec(dllexport) および __declspec(dllimport) ディレクティブを使用します。ただし、テンプレートでは機能しません。それを機能させる方法はありますか?

「extern」を使用する提案されたソリューションをいくつか見ましたが、私のコードは Visual Studio 2002 および 2005 で動作するはずなので、使用できないと思います。

ありがとうございました。

明確化: テンプレートのインスタンス化の異なるタイプごとに、静的変数の異なるインスタンスが必要です。しかし、2 つの異なる dll で同じタイプのテンプレートをインスタンス化する場合、両方で同じ変数を使用したいと考えています。

4

7 に答える 7

4

次の解決策もあります。

  • ライブラリ内: テンプレートの特殊化を明示的にインスタンス化し、それらを dllexport と共有します。
  • メインプログラムで:
    • 特殊化が利用可能な場合は、ライブラリから使用されます
    • 特殊化が利用できない場合、メインプログラムでコンパイルされます

これを行う方法の詳細な説明:

Anteru のブログ 明示的なテンプレートのインスタンス化

于 2009-06-30T18:05:35.553 に答える
3

問題は、それぞれの異なるテンプレートのインスタンス化が、異なるテンプレートパラメータを持つ他のインスタンスと共有されない独自の静的変数を持つ異なるタイプであるということです。静的変数を含む非テンプレート基本クラスを提供できます。

于 2008-12-29T17:21:24.597 に答える
2

テンプレート クラスを使用するコードの制限を少なくして、これを行う方法があるようです。

静的メンバーをポインターにします。既知の型が固定され、DLL からエクスポートできるグローバル マップを作成します。マップは、クラスの typeid() をキーとして使用し、「クラスごとのグローバル変数」のアドレスを値として使用します。クラスがマップに既に存在するかどうかをテストする関数を使用して静的メンバーを初期化し、存在する場合は (2 番目の DLL 内の) クラスの 2 番目のバージョンがクラスの最初のバージョンの静的変数を指すように強制します。

このように、すべての DLL には個別の静的オブジェクトがありますが、すべての DLL にもポインターがあり、すべてのポインターは同じ静的オブジェクトを指しています。

static の型がテンプレート パラメーターと同じであると仮定した疑似コードを次に示します (ただし、他の場合にも簡単に適用できるはずです)。

map<string,void*> dllexport the_map;  // instantiate this once in a single DLL

T *set_the_global(T *candidate) {
  map<string,void*>::iterator r = the_map.find(string(typeid(the_class<T>).name()));
  if(r == the_map.end()) {
    the_map[string(typeid(the_class<T>).name())] = (void*)candidate;
    return candidate;  // new class: use it as global storage location
  } else {
    return (T*)(r->second);  // class already has global storage location
  }
}

template <class T> class the_class {
  virtual void something();  // so RTTI exists
  static T *the_global;  // use this! always points to the same object
  static T one_per_dll;  // only used in initialisation
};
template<class T> the_class<T>::one_per_dll;
template<class T> the_class<T>::the_global = set_the_global(&the_class<T>::one_per_dll)
于 2009-12-18T15:20:06.390 に答える
2

テンプレートの特殊化を作成してから、特殊化の静的メンバーをエクスポートします。

于 2008-12-29T17:12:16.737 に答える
1

あなたはすでにこの使用法を試しています:

#pragma data_seg(".JOE")
HWND hWndServer = NULL;
HHOOK hook = NULL;
#pragma data_seg()
#pragma comment(linker, "/section:.JOE,rws")  

変数にはビームを初期化する必要があることに注意してください。

詳細:http: //msdn.microsoft.com/en-us/library/ms997537.aspx http://www.flounder.com/hooks.htm

幸運を。

于 2008-12-29T17:27:24.320 に答える
1

この問題には 2 つの修正方法があります。

まず、テンプレートではない別のクラスを使用して、この静的な値を保持するか、グローバルにしますか? -そしてそれをdllからエクスポートします。

もう 1 つは、コード内でテンプレートをインスタンス化し、そのインスタンス化されたテンプレート値をエクスポートするという点で、やや複雑です。例を挙げると、特別な種類のリンク リスト テンプレート クラスがあり、DLL 間で静的な値を共有する必要があったとします。テンプレート化するコードを書きましたが、実際に使用されるのは少数の型だけです。クラスを次のようにインスタンス化します。

template <class T> class Foo;
template<> class Foo<int> {};

次に、含まれている静的変数をエクスポートできます。

__declspec(dllexport) int Foo<int>::StaticMember = 0;

(またはそのようなもの、私はdllのエクスポート/インポートを行うことに少し慣れていません。)

本当の問題は、なぜこれを行う必要があるのか​​ということですが、技術的には、メモリに 1 つのコピーしか格納されていないプロセス間で DLL を使用できるためです。すべてのプロセスに対して静的バージョンを 1 つだけにするか、プロセスごとに 1 つだけにするか。

于 2008-12-29T17:14:08.370 に答える
0

extern templateインスタンス化がドラフト標準に受け入れられる前に、Microsoft は VC++ コンパイラの拡張機能を実装したようです。

非標準の拡張機能が使用されている場合、VC++ コンパイラは警告を生成します。VS.NET (2003) 以降の詳細については、この警告の説明を参照してください。この警告は、VS 6.0に対しても表示されます。

私は個人的にこの拡張機能を使用しようとしたことがないため、この提案を保証することはできません. 明らかに、私はこの回答を Microsoft Visual Studio に制限しています (Unix に関するあなたからのコメントを見ました) が、それが役立つことを期待して投稿します。

于 2008-12-29T19:52:37.240 に答える