How to declare enumerator values inside a macro?

134 views Asked by At

Preamble: This question is relatively high-level, do not feel any pressure to answer to the question directly. For example, if you believe in a better design approach, please let me know.

Why we need this:

We are making a software that should be easily modifiable, use ECS design pattern and follow Open-Closed principle. This creates the following requirements:

  1. Objects hold a FeatureList, which is a bitfield where each bit represents a Component, as per common Entity-Component Systems.
  2. When coding new Features, there is no need to #include them anywhere in the program. This should make it more user-friendly to code in and more modifiable.
  3. Features should not have hard-coded values. This should make it quick to disable, change and reformat features.

And this can all be done: Minimal reproducible example and a simplified UML diagram

And as you can test out yourselves the code works.

Issue:

However, we have a a big design issue: (Not the crash if we go higher than second bit, this was a minimal example)

ExampleObject->FeatureList |= (1 << 0); // Spawn Feature1
ExampleObject->FeatureList |= (1 << 1); // Spawn Feature2
ExampleObject->FeatureList |= (1 << 2); // Spawn Feature3

As you can see, we have hard-coded feature values. This breaks our third requirement. These hard-coded values are also based on compile order, which isn't ideal.

This can be fixed with a search algorithm to find integers from std::unordered_map<int, std::string> Map;. Example code would look like this:

ExampleObject->FeatureList |= (1 << FeatureRegistry::GetInstance().GetFeatureValue("Feature1"));
ExampleObject->FeatureList |= (1 << FeatureRegistry::GetInstance().GetFeatureValue("Feature2"));
ExampleObject->FeatureList |= (1 << FeatureRegistry::GetInstance().GetFeatureValue("Feature3"));

But this requires usage of hard-coded strings: If a Feature's name were to change or be completely removed, there would be no quick way to replace this name across the codebase or disable Feature spawning. (We'd have to rely on compiler errors, which isn't ideal)

There is one solution that handles Names-to-Integers without hardcoding the values: Enumerators. We can even use autocompletion on most IDEs to make it clear what we can and cannot spawn, as well as replace names and set values to null easily!

So we'd need an enumerator which has a defined value for each registered Feature.

This is very simple: Add an enumerator into REGISTER_FEATURE macro, and… There isn't a clear way forward here. There is no information of dynamically allocating enumerators or declaring enumerators inside macros shared between between multiple files: There are opaque and anonymous enumerator declarations, but it is not clear how these can be utilized.

Final question:

How to declare enumerator values inside a macro?

0

There are 0 answers