Saturday, 16 July 2016

Best way to for C++ types to self register in a list?



Suppose I have some per-class data: (AandB.h)



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

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


... and lots and lots more classes. And I want to do something like:



persistenceSystem::registerPersistableType( A::getPersister() );
persistenceSystem::registerPersistableType( B::getPersister() );
...
persistenceSystem::registerPersistableType( Z::getPersister() );


... for each class.



My question is: is there a way to automate building a list of per-type data so that I don't have to enumerate each type in a big chunk (as in the above example)?



For example, one way you might do this is: (AutoRegister.h)



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

AutoRegisterBase* next;
};

template
struct AutoRegister : public AutoRegisterBase
{
AutoRegister() { next = getHead(); getHead() = this; }

virtual void registerPersist()
{
persistenceSystem::registerPersistableType( T::getPersister() );
}
};


and use this as follows: (AandB.cxx: )



static AutoRegister auto_a;
static AutoRegister auto_b;


Now, after my program starts, I can safely do: (main.cxx)



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


to collect each piece of per-type data and register them all in a big list somewhere for devious later uses.



The problem with this approach is that requires me to add an AutoRegister object somewhere per type. (i.e. its not very automatic and is easy to forget to do). And what about template classes? What I'd really like is for the instantiation of a template class to somehow cause that class to get automatically registered in the list. If I could do this I would avoid having to have the user of the class (rather than the author) to remember to create a:



static AutoRegister< SomeClass > auto_X1;
static AutoRegister< SomeClass > auto_X2;
...
etc....


for each template class instantiation.



For FIW, I suspect there's no solution to this.


Answer



You can execute something before main once if a instantiation of a template is made. The trick is to put a static data member into a class template, and reference that from outside. The side effect that static data member triggers can be used to call the register function:



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

static exec_register register_object;
static ref_it referrer;
};

template typename automatic_register::exec_register
automatic_register::register_object;


Derive the class you want to be auto-registered from automatic_register . The register function will be called before main, when the declaration of referrer is instantiated (which happens when that class is derived from, which will implicitly instantiate that class from the template).



Having some test program (instead of the register function, a function do_it is called):



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

int main() {
std::cout << " main ";
}


Yields this output (as expected):



doit main

No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...