I'm using C++ 11. I have N source files each containing a class that inherits from a common base class. At startup, I want each class to register itself into a collection. The registration is to include 1) data necessary for identifying the purpose of the class, 2) a class factory for creating instances of the class. The number of source files is unknown. What is the pattern for doing this? The solution needs to be cross-platform compatible with Visual Studio 2013, gcc and others.
Using @Pawel's suggestion, I've created an example. The goal is to create a registration process that collects a list of classes, each registration having a class factory and arbitrary data. Specifically, this example registers Mime classes into a std::map. The registration entry holds a vector of content type strings, and a class factory for creating the Mime class.
In each source file, I use a one liner to register the class. A vector of content types is passed to specify the class's supported types. Every class inherits from a base class named Mime (not shown).
RegisterTypes<Swagger> swagger(vector<const char *>({ "application/swagger+json" }));
In a header file, define a struct to contain a registration entry. Two initializers are needed, a vector of content types, and the class factory (implemented as a lamda).
struct Registry
{
public:
Registry() {} // initializer below forces this initializer to be needed
Registry(vector<const char *> ct, function<Mime*(void)> cf) : contentTypes(ct), classFactory(cf) {}
vector<const char *> contentTypes;
function<Mime*(void)> classFactory;
};
In a header file, extern a std::map which will contain the registrations. Each map entry consists of a key and a registration struct. The actual definition is in a .cpp file (not shown). The registry uses a struct so it can hold multiple values.
extern std::map<const string, struct Registry> Mimes;
In the header file, define the registration class. Each instantiation of the registration class will create a registration entry in a std::map. In this example, the registration class creates a registration entry consisting of a key (class name), a vector of supported content types, and a class factory. The class factory creates instances of the class and is implemented as a lamda. Every registered class has a common base class of Mime.
template<class T> class RegisterTypes
{
public:
RegisterTypes(vector<const char *> contentTypes)
{
Mimes[typeid(T).name()] = { contentTypes, [](void) -> Mime * { return (Mime *)(new T()); } }; // requires a matching explicit initializer
}
};