C++ での自動クラス登録は一般的なタスクであり、StackOverflow に関するよくある質問です。
基本的な目的は、クラスをいくつかのレジストリまたはファクトリに自動的に登録して、後で各クラスを処理できるようにすることです。
これは確立された手法であり、(たとえば) Google Test ( http://code.google.com/p/googletest ) などのライブラリで使用され、Test クラスのサブクラスを自動的に登録して、各テストを自動的にインスタンス化できるようにします。テスト実行中に実行します。
登録は、コンストラクターが登録を行う静的な Registrar クラスをインスタンス化するか、CRTP を巧みに使用して基本クラスのコンストラクターに登録コードを配置するか、任意の方法で行うことができます (上記のリンクでは、いくつかの異なる手法が提供されています)。
ただし、これらの手法を実装すると、スケーリングが非常に不十分であることがわかります。Google Test で 10,000 の TEST マクロを呼び出すと、コンパイルとリンクが停止し (MSVC 2010)、バイナリ サイズが爆発的に増加します。これを別の方法で実装すると、静的レジストラーで 10,000 のサブクラスを使用しても、同じ動作が見られます。
たとえば、単純化された例を考えてみましょう。
#include <iostream>
#include <string>
class Base {
public:
Base( const std::string& Name_ ) : Name( Name_ ) { ; }
~Base() { ; }
virtual std::string GetName() const { return Name; }
virtual void DoSomething() = 0;
private:
std::string Name;
};
class Registry {
public:
static Registry& GetInstance() {
static Registry* Instance = new Registry();
return *Instance;
}
void Register( const Base* b ) {
std::cout << "Registered class " << b->GetName() << std::endl;
}
private:
Registry() { ; }
~Registry() { ; }
};
class Registrar {
public:
Registrar( const Base* b ) {
Registry::GetInstance().Register( b );
}
~Registrar() { }
};
#define REGISTER( CLASS ) \
class CLASS : public Base { \
public: \
CLASS( const std::string& Name ) : Base( Name ) { ; } \
virtual void DoSomething(); \
private: \
static Registrar m_Registrar; \
}; \
Registrar CLASS::m_Registrar( new CLASS( #CLASS ) ); \
void CLASS::DoSomething()
int main( int argc, char** argv )
{
return 0;
}
REGISTER( Class1 )
{
std::cout << "Doing something in Class1" << std::endl;
}
REGISTER( Class2 )
{
std::cout << "Doing something in Class2" << std::endl;
}
[...]
合計 10000 回の自動生成された REGISTER 呼び出し。
これがうまくスケーリングできない根本的な理由はありますか? コンパイラは 10000 個のクラスで停止しますか? MSVC 2010 では、かなり高速なマシンで上記のコンパイルに約 2 分かかり、サイズが 5 MB を超えるバイナリが生成されます。Google Test で同様のことを行うと、同じ結果が得られます。