C++类型在列表中自行注册的最佳方法是什么?

use*_*956 10 c++

假设我有一些每类数据:(AandB.h)

class A
{
public:
   static Persister* getPersister();
}

class B
{
public:
   static Persister* getPersister();
}
Run Code Online (Sandbox Code Playgroud)

......还有很多课程.我想做的事情如下:

persistenceSystem::registerPersistableType( A::getPersister() );
persistenceSystem::registerPersistableType( B::getPersister() );
...
persistenceSystem::registerPersistableType( Z::getPersister() );
Run Code Online (Sandbox Code Playgroud)

......为每个班级.

我的问题是:有没有办法自动构建每类数据列表,这样我就不必枚举大块中的每个类型(如上例所示)?

例如,您可以这样做的一种方法是:(AutoRegister.h)

struct AutoRegisterBase
{
   virtual ~AutoRegisterBase() {}
   virtual void registerPersist() = 0;
   static AutoRegisterBase*& getHead()
   {
      static AutoRegisterBase* head= NULL;
      return head;
   }

   AutoRegisterBase* next;
};

template <typename T>
struct AutoRegister : public AutoRegisterBase
{
   AutoRegister() { next = getHead(); getHead() = this; }

   virtual void registerPersist()
   {
       persistenceSystem::registerPersistableType( T::getPersister() );
   }
};
Run Code Online (Sandbox Code Playgroud)

并使用如下:(AandB.cxx :)

static AutoRegister<A> auto_a;
static AutoRegister<B> auto_b;
Run Code Online (Sandbox Code Playgroud)

现在,在我的程序启动后,我可以安全地做到:(main.cxx)

int main( int, char ** )
{
    AutoRegisterBase* p = getHead();
    while ( p )
    {
        p->registerPersist();
        p = p->next;
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

收集每个类型的每个数据并将它们全部放在一个大的列表中,以便以后使用.

这种方法的问题是需要我在每个类型的某处添加一个AutoRegister对象.(即它不是很自动,很容易忘记).那么模板类呢?我真正喜欢的是模板类的实例化以某种方式导致该类自动在列表中注册.如果我能做到这一点,我将避免让类的用户(而不是作者)记住创建一个:

static AutoRegister< SomeClass<X1> > auto_X1;
static AutoRegister< SomeClass<X2> > auto_X2;
...
etc....
Run Code Online (Sandbox Code Playgroud)

对于每个模板类实例化.

对于FIW,我怀疑没有解决方案.

Joh*_*itb 9

如果进行模板实例化,则可以在main之前执行一次.诀窍是将静态数据成员放入类模板,并从外部引用它.静态数据成员触发的副作用可用于调用寄存器函数:

template<typename D>
struct automatic_register {
private:
    struct exec_register {
        exec_register() {
            persistenceSystem::registerPersistableType(
                D::getPersister()
            );
        }
    };
    // will force instantiation of definition of static member
    template<exec_register&> struct ref_it { };

    static exec_register register_object;
    static ref_it<register_object> referrer;
};

template<typename D> typename automatic_register<D>::exec_register 
    automatic_register<D>::register_object;
Run Code Online (Sandbox Code Playgroud)

派生您想要自动注册的课程automatic_register<YourClass>.当referrer实例化声明时(在从该类派生时发生,将从模板中隐式实例化该类),将在main之前调用register函数.

有一些测试程序(而不是寄存器函数,调用函数do_it):

struct foo : automatic_register<foo> {    
    static void do_it() {
        std::cout << " doit "; 
    } 
}; 

int main() { 
    std::cout << " main "; 
}
Run Code Online (Sandbox Code Playgroud)

产生此输出(如预期):

doit main
Run Code Online (Sandbox Code Playgroud)

  • Johannes,你的"doit main"示例编译得很好,但是使用Visual Studio 10(SP1)只输出"main".我们都知道VS并不是最符合标准的兼容编译器,但是你有另一种解决方案可以更容易地移植到VS和GCC以及Clang吗? (2认同)