2012-03-03 6 views
4

静的オブジェクトを正常に初期化しようとしています。目的は、ファクトリクラスをリポジトリ(シングルトン)に自動的に登録することです。私はすでに見ていただ静的オブジェクトの初期化を強制しようとしました

How to force a static member to be initialized?

コメントの一つは、(私が続いてきたことを例もある)と述べている:

私はCでそれを読ん++標準(14.7.1):クラステンプレートのメンバまたはメンバテンプレートが明示的にインスタンス化されていないか、または明示的に特殊化されていない限り、メンバ定義が存在する必要があるコンテキストで特殊化が参照されると、メンバの特殊化は暗黙的にインスタンス化されます。静的データメンバの定義が必要な方法で静的データメンバ自体が使用されていない限り、静的データメンバの初期化(および関連する副作用)は発生しません。

私は同様のことをしようとしていますが、オブジェクトの初期化を強制することはできません。ここにコードがあります。私は何が欠けているのか分からない。これは私が使用しているテンプレートです。

namespace my_lib 
{ 
    template <typename T> 
    struct FactoryHelper 
    { 
     FactoryHelper(); 
     static FactoryHelper<T> _helper; 
    }; 
} 

、これはライブラリのユーザは、ファクトリクラスを定義し、同時に、リポジトリ内のオブジェクトを登録するために使用することがマクロである:

#define CREATE_FACTORY(ClassName)\ 
namespace my_lib\ 
{\ 
    class ClassName##Factory;\ 
    template<> FactoryHelper<ClassName##Factory>::FactoryHelper() { std::cout << "object initialized!" << std::endl; }\ 
    template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper;\ 
    struct ClassName##Factory : public FactoryBase<ClassName> {\ 
     ...\ 
    };\ 
} 

以前コードされますヘッダーファイル(Factory.h)で定義されています。 .cppファイル(Example.cpp)で

、私が持っている:私はプログラムを実行すると、それが呼び出されたときに

CREATE_FACTORY(UnitTestExample) 
... 

、私はそのコンストラクタプリントメッセージを見ることができません。どんな援助も大歓迎です。

ありがとうございます。

答えて

4

これはC++のトリッキーな領域です。ここでは、静的メンバーをここで定義しようとしています:

template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper;\ 

これは実際には宣言であり定義ではありません。 C++が定義として扱うためには、何かをコンストラクタに渡す必要があります。一般的に、これはあなたにそれを初期化する値である:

template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper = FactoryHelper<ClassName##Factory>();\ 

しかし、あなたの場合、あなたはおそらくそれがコピー可能になりたくないので、これは、シングルトンになりたいです。 、言っ

#include <iostream> 

namespace my_lib 
{ 
    template<typename> struct FactoryBase { }; 
    template <typename T> 
    struct FactoryHelper 
    { 
     FactoryHelper (int); 
     static FactoryHelper<T> _helper; 
    }; 
} 

#define CREATE_FACTORY(ClassName)\ 
namespace my_lib\ 
{\ 
    class ClassName##Factory;\ 
    template<> FactoryHelper<ClassName##Factory>::FactoryHelper (int) { std::cout << "object initialized!" << std::endl; }\ 
    template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper(0);\ 
    struct ClassName##Factory : public FactoryBase<ClassName> {\ 
    };\ 
} 

struct UnitTestExample { 
}; 

CREATE_FACTORY(UnitTestExample); 

int main(int argc,char **argv) 
{ 
    return 0; 
} 

:ここでは完全な実施例である

template<> FactoryHelper<ClassName##Factory>::FactoryHelper (int) { std::cout << "object initialized!" << std::endl; }\ 

を:その場合は、あなたは、いくつかのダミーパラメータが必要です。

template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper(0);\ 

を、あなたが適切にあなたのコンストラクタを変更する必要があります他の回答の中のいくつかの提案を使用することは、より良い設計決定であるかもしれません。

定義対明示的な特殊宣言の詳細については、ここで見つけることができます:static member initialization for specialized template class

+0

まず、提案と説明の両方に感謝します。私はあなたが私に与えたソリューションをコードに加えて動作させませんでした。その後、私は独立型のプログラムをやろうとしていました。 違いは、実装しているクラスがコンパイルされ、実行可能ファイルに静的ライブラリとしてリンクされていることです。静的ライブラリを使わずにコードをまとめてコンパイルすると動作します。 なぜ静的オブジェクトの初期化に影響しますか? ありがとう! – user1192525

+1

私はここで応答が見つかりました: http://stackoverflow.com/questions/1804606/static-initialization-and-destruction-of-a-static-librarys-globals-not-happenin – user1192525

1

あなたのマクロが行うことは、クラスのいくつかのメンバーの特殊化を宣言することです。これはどんなオブジェクトも作成しませんし、おそらくあなたが本当に望むものではないでしょう。あなたはどこかにFactoryHelper<SomeClass>::_helperの定義が必要です。私は全然進むべき道だとは思わない、と述べた

FactoryHelper<foo> FactoryHelper<foo>::_helper; 

:あなたが本当に必要なのは、工場の機能を登録する何かをインスタンス化することです静的メンバの定義は次のようになりますこれははるかに簡単に行うことができます。特に、マクロを使用する必要はありません。ここで

は、私はこれを行う方法は以下のようになります。これは、あなたがタイプbaseから派生したオブジェクトを作成することや、あなたの工場は、オブジェクトコンストラクタ関数としてstd::auto_ptr<base>を返す機能するマッピングを使用していることを前提とし、それが持っている

template <typename T> 
struct factory_helper 
{ 
    std::auto_ptr<base> create_fuction() { return std::auto_ptr<base>(new T()); } 
    factory_helper(std::string const& name) { 
     factory.register_class(name, create_function); 
    } 
}; 

register_class()関数は、名前とコンストラクタ関数をパラメータとして取ります。これらの前提はどちらもapprachに固有のものではありません。これはあなたが言及しなかったいくつかの空白を埋めることに過ぎません。あなたは、このようなクラスfoo何かのためファクトリ関数を登録します:

static factor_helper<foo> foo_helper("foo"); 
0

代わりの静的メンバ(あなたがどこかに作成する必要があります)、静的関数に静的変数の可能性を検討

のような
namespace my_lib 
{ 
    template <typename T> 
    struct FactoryHelper 
    { 
     FactoryHelper() { ... }; 
     static FactoryHelper<T>& helper() 
     { static FactoryHelper<T> h; return h; } 
    }; 
} 

あなたが求めているのと同じではありませんが、帯域外の初期化は必要ありません。

0

まあ、提案や説明の両方のためのすべてのおかげでたくさんの最初の。私はあなたが私に与えたソリューションをコードに加えて動作させませんでした。そして、あなたのソリューションをスタンドアロンプ​​ログラムとして試してみました。

違いは、実装しているクラスがコンパイルされ、実行可能ファイルに静的ライブラリとしてリンクされていることです。静的ライブラリを使わずにコードをまとめてコンパイルすると動作します。

私はここで応答が見つかりました:彼らはメインアプリケーションから参照されていない限りStatic initialization and destruction of a static library's globals not happening with g++

.oファイルがリンクされていません。私はldオプション-Wl,--whole-archiveを使用しましたが、今は動作します。

-Wl,--whole-archive -lmy_static_library ... -Wl,--no-whole-archive 

2番目の質問に関連して、コンストラクタにダミーパラメータを指定する必要がある理由はまだ分かりません。

template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper(0);\ 

むしろこれを行うより:

emplate<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper = FactoryHelper<ClassName##Factory>();\ 

ありがとう!

+0

宣言対定義の問題かなりトリッキーです。私はどこでも良い説明を見つけていない。私はより詳細に説明したいと思いますが、私の元の答えの範囲をはるかに超えているようです。 –

+0

実際、この説明はまともです:http://stackoverflow.com/questions/2342550/static-member-initialization-for-specialized-template-class –

関連する問題