Somehow register my classes in a list
Here is method to put classes names inside a vector. Leave a comment if I missed important details. I don't think it will work for templates, though.
struct MyClasses {
static vector<string> myclasses;
MyClasses(string name) { myclasses.push_back(name); }
};
#define REGISTER_CLASS(cls) static MyClasses myclass_##cls(#cls);
struct XYZ {
};
REGISTER_CLASS(XYZ);
The trick here is to make some computation before main() is called and you can achieve this via global initialization. REGISTER_CLASS(cls) actually generates code to call the constructor of MyClasses at program startup.
UPDATE: Following gf suggestion you can write this:
#define REGISTER_CLASS(cls) temp_##cls; static MyClasses myclass_##cls(#cls); class cls
class REGISTER_CLASS(XYZ) { int x, y, z; }
Best way to for C++ types to self register in a list?
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<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;
Derive the class you want to be auto-registered from automatic_register<YourClass>
. 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<foo> {
static void do_it() {
std::cout << " doit ";
}
};
int main() {
std::cout << " main ";
}
Yields this output (as expected):
doit main
Can a factory somehow determine all possible classes, by looking in a particular file?
You can write a parser and have the class process the input file, but I doubt that's what you want.
You can also use the crtp pattern to your advantage:
template<class T>
struct Base
{
Base()
{
reg;
}
virtual std::string name() = 0;
static bool reg;
static bool init()
{
T t;
Factory::registerClass(t.name());
return true;
}
};
template<class T>
bool Base<T>::reg = Base<T>::init();
source
You'd then derive classes as
struct Derived1 : Base<Derived1>
{
...
}
This would automatically register your class with Factory
given its name (you have to implement name
in non-abstract classes because it's pure).
Additionally, you can pass a callback to registerClass
that knows how to create your derived class.
Scalable automatic class registration in C++
Writing Java code in C++ rarely works well. All those heap allocations are probably what's killing performance (as they would in Java, but Java startup is so slow that nobody would notice). Use static objects, and don't put a Registrar
object into each generated class; that's just a waste of time and space.
Instantiating classes by name with factory pattern
Here is a generic factory example implementation:
template<class Interface, class KeyT=std::string>
struct Factory {
typedef KeyT Key;
typedef std::auto_ptr<Interface> Type;
typedef Type (*Creator)();
bool define(Key const& key, Creator v) {
// Define key -> v relationship, return whether this is a new key.
return _registry.insert(typename Registry::value_type(key, v)).second;
}
Type create(Key const& key) {
typename Registry::const_iterator i = _registry.find(key);
if (i == _registry.end()) {
throw std::invalid_argument(std::string(__PRETTY_FUNCTION__) +
": key not registered");
}
else return i->second();
}
template<class Base, class Actual>
static
std::auto_ptr<Base> create_func() {
return std::auto_ptr<Base>(new Actual());
}
private:
typedef std::map<Key, Creator> Registry;
Registry _registry;
};
This is not meant to be the best in every circumstance, but it is intended to be a first approximation and a more useful default than manually implementing the type of function stijn mentioned. How each hierarchy should register itself isn't mandated by Factory, but you may like the method gf mentioned (it's simple, clear, and very useful, and yes, this overcomes the inherent problems with macros in this case).
Here's a simple example of the factory:
struct Base {
typedef ::Factory<Base> Factory;
virtual ~Base() {}
virtual int answer() const = 0;
static Factory::Type create(Factory::Key const& name) {
return _factory.create(name);
}
template<class Derived>
static void define(Factory::Key const& name) {
bool new_key = _factory.define(name,
&Factory::template create_func<Base, Derived>);
if (not new_key) {
throw std::logic_error(std::string(__PRETTY_FUNCTION__) +
": name already registered");
}
}
private:
static Factory _factory;
};
Base::Factory Base::_factory;
struct A : Base {
virtual int answer() const { return 42; }
};
int main() {
Base::define<A>("A");
assert(Base::create("A")->answer() == 42);
return 0;
}
Related Topics
How to Implement Timeout for Function in C++
Differencebetween C-Like Casting and Functional Casting
How Is Heap and Stack Memories Managed, Implemented, Allocated
C++ Comparison of Two Double Values Not Working Properly
How-To Write a Password-Safe Class
C++ Concept That Requires a Member Function with an Outputiterator as Parameter
Paint a Rect on Qglwidget at Specifit Times
How to Build Google's Protobuf in Windows Using Mingw
Function to Mangle/Demangle Functions
Write and Read String to Binary File C++
Convert a Unicode String in C++ to Upper Case
Does Accessing the First Field of a Struct via a C Cast Violate Strict Aliasing
What's the Difference Between a Const Member Function and a Non-Const Member Function
Why Do Reference Type Members Cause Implicitly-Declared Copy Assignment Operator to Be Deleted