It is possible to automatically stitch code together without explicit lines to do so, by using global objects and their constructors. This is a technique used by unit test frameworks, among others.

What does this look like?

class ObjectOne
{
public:
	ObjectOne() {}
} ObjectOne_instance;

This will declare a class and create a global instance of it. At runtime, before main, all the constructors for global objects are called, including ObjectOne::ObjectOne(). Of course, this constructor does nothing, but it does run (usually - see linker issues).

We want to do something specific. Assume we have a base class Object and a Object::Register function that adds this object to some list. We’re going to make this a static function.

class Object
{
public:
	Object() {}
	static void Register(Object* o) { Add(Registry(), o); }

};

class ObjectOne : Object
{
public:
	ObjectOne() { Register(this); }
} ObjectOne_instance;

Now, when we run, this will call Register with our this pointer. We would like to have this insert into a list of Objects. We can do this without allocation if we use an intrusive linked list where the pointers are part of each (statically allocated) object.

class Object
{
public:
	Object() { next = nullptr; last = this; }
	static void Register(Object* o) { Add(Registry(), o); }
	static Object& Registry() { static Object registry; return registry; }
	static void Add(Object& head, Object* o)
	{
		if (head.next == nullptr)
			head.next = o;
		else
			head.last->next = o;
		head.last = o;
	}
	Object* next;
	Object* last;
};

class ObjectOne : public Object
{
public:
	ObjectOne() { Register(this); }
} ObjectOne_instance;

Of course, it’s not enough to just build a list. We want to use it. In particular, we want to call a Run() method on each object in the list.

class Object
{
public:
	Object() { next = nullptr; last = this; }
	static void Register(Object* o) { Add(Registry(), o); }
	static Object& Registry() { static Object registry; return registry; }
	static void Add(Object& head, Object* o)
	{
		if (head.next == nullptr)
			head.next = o;
		else
			head.last->next = o;
		head.last = o;
	}
	virtual void Run() {}
	static void RunAll()
	{
		for (auto n = Registry().next; n != nullptr; n = n->next)
			n->Run();
	}
	Object* next;
	Object* last;
};

class ObjectOne : public Object
{
public:
	ObjectOne() { Register(this); }
	void Run() { /* do something */ }
} ObjectOne_instance;

int main(int argc, char* argv[])
{
    Object::RunAll();
}

This is a lot of scaffolding to do nothing. But we have a building block that doesn’t allocate before main, adds all our objects into a list (in a compiler-specific order), and then lets us iterate the list at some point.

We can hide some of the boilerplate with macros. Instead of declaring each new class to register a Run function, we have a macro create and register the object for us, and we just supply the body of the Run function.

#define OBJECT(name) \
class Object ## name : public Object \
{ \
public: \
    Object ## name () { Register(this); } \
    void Run(); \
} Object ## name ## instance; \
void Object ## name :: Run()

OBJECT(one)
{
    printf("Hello from one\n");
}

The idea is that the macro and the Object class are in some header file that we include, and then our task is just to write OBJECT bodies. We have to give each one a unique name, but this is no different than the need to give each global function a unique name.

This is a factory of sorts. What if we want more than one factory? Well, we can parameterize the factory itself, and pass that to the OBJECT macro, either as a parameter, or by nesting OBJECTs inside a scope we create.

And we can continue to elaborate. We can provide sort orders - once all the objects are registered, we could re-sort however we want. We could have multiple lists either as explicit separate factories, or with parameters in the objects and passed to the RunAll method.

Keep it simple. Don’t add functionality you won’t need.

TBD - add note about linker challenges when doing this.