You describe different problems right away. As for the specific problem with some kind of static initialization, a simple approach is to create a fake class that will do the registration. Then each of the different classes can have a member static const X , the member must be defined in the translation block, and the definition will initiate the instantiation and registration of the class.
This does not solve the complex problem, which is a fiasco of the initialization order. The language does not provide any guarantees on the order of initialization of objects in different translation units. That is, if you compile three translation units with such classes, there is no guarantee regarding the relative execution order of the fake participant. This also applies to the library: there is no guarantee that the container into which you want to register your classes has been initialized if such a container is an attribute of the global / static member.
If you have access to the code, you can change the container code to use static local variables , and this will be a step forward to ensure the initialization order. As an outline of a possible solution:
Now, in this case, there is no specific registration order for classes a and b , but this may not be a problem. On the other hand, using a local static variable in the registry::instance function, the singlet must be initialized before any call to the registry::register methods (as part of the first call to the instance method),
If you cannot make this change, you are mostly out of luck, and you cannot guarantee that the registry will be created before other static member attributes (or global characters) in other translation units. If this is the case, you will have to postpone the registration of the class until the first instance and add code to the constructor of each registered class, which ensures that the class is registered before the actual construction of the object.
This may or may not be a solution, depending on whether other code creates objects of type or not. In the particular case of the factory function (the first of which came to mind), if no one else is allowed to create objects of types a or b ..., then copying the signature to the constructor calls will not be a solution either.