I'm trying to reduce the boilerplate of a lot of header-only classes I'm using. Each of these classes must go through a registration step. I want this step to be defined in the same file as the class definition.
I came to the following solution (-std=c++17
required):
#include <iostream>
#include <typeinfo>
template<typename T>
bool __autoRegisteringFunction() {
std::cout << "Registering: " << typeid(T).name() << std::endl;
return true;
}
#define REGISTER_CLASS(TYPE) \
inline static const bool __registered = __autoRegisteringFunction<TYPE>();
class Foo {
REGISTER_CLASS(Foo)
};
class Bar {
REGISTER_CLASS(Bar)
};
int main() {
return 0;
}
While doing some research, I realized it was even possible to skip the class name in the macro by being clever (inspired from this library):
#include <iostream>
#include <typeinfo>
template<typename T>
bool __autoRegisteringFunction() {
std::cout << "Registering: " << typeid(T).name() << std::endl;
return true;
}
template<typename T>
struct __AutoRegisteringClass {
inline static const bool __registered = __autoRegisteringFunction<T>();
};
#define REGISTER_CLASS() \
const void* __autoRegisteringMethod() const { \
return &__AutoRegisteringClass<decltype(*this)>::registered; \
}
class Foo {
REGISTER_CLASS()
};
class Bar {
REGISTER_CLASS()
};
int main() {
return 0;
}
Note that I simplified the example. The macro I plan to use needs more parameters, not requiring to pass the class name would both avoid possible typos and reduce repeatability. That's why I'm interested in the 2nd solution.
From what I tested it works quite well. I still have a few questions:
- Is the first solution safe from the "static initialization order fiasco"?
- Is using a dummy method (never called) for instantiating a template thanks to
decltype(*this)
a common practice (or a known trick) in C++ meta-programming? - Would you consider the given implementations well defined by standards and thus globally safe to use?
- Could the pattern I'm willing to use be somehow simplified?
inline static
member variables at construction time. \$\endgroup\$