mardi 20 juin 2023

Implementing Dynamic Enumeration with X-Macros in C

I came across an issue: I needed an enumeration, where the value could never be invalid. There doesn't seem to be a design pattern for this, so I'll call this Dynamic Enumeration:

Usually, an enumerator is created in the following way:

#include <iostream>

enum MyEnum {
    Value1,
    Value2
};

int main() {
    MyEnum value = Value2;
    std::cout << value << std::endl;  // Output: 1

    return 0;
}

However, by utilizing X-macros, we can split the definition of MyEnum between multiple files:

main.ccp:

#include <iostream>
#include "EnumValues.h"

#define ENUM_VALUES_1 \
    ENUM_VALUE(Value1) \

#define ENUM_VALUES_2 \
     ENUM_VALUE(Value2)

#define ENUM_VALUES \
    ENUM_VALUES_1 \
    ENUM_VALUES_2

enum MyEnum {
    ENUM_VALUES
};

#undef ENUM_VALUE
#undef ENUM_VALUES_1
#undef ENUM_VALUES_2

int main() {
    MyEnum value = Value2;
    std::cout << value << std::endl;  // Output: 1

    return 0;
}

Enums.h:

#pragma once

#define ENUM_VALUE(x) x,

EnumValues.h:

#pragma once
#include "Enums.h"

#define ENUM_VALUES_1 \
    ENUM_VALUE(Value1) \

#define ENUM_VALUES_2 \
     ENUM_VALUE(Value2)

This can be used to create a useful design pattern: A single-argument macro that can define enumerator values, without touching the definition of the enumerator directly:

CREATE_ENUM(Foo); // Defines Foo-feature as an enumerator value for MyEnum.

This allows for dynamic enumeration: For example, You can create an enumerator of all functioning features, where only compiled features exist as enumerator values. The specific integer value of each enumerator is undefined, but each enumerator must have been compiled, preventing the use of empty, unused enumerator values.

However, it is not clear how this 'single-argument macro' can be created: The issue lies within this #define block:

#define ENUM_VALUES \
    ENUM_VALUES_1 \
    ENUM_VALUES_2

Manually listing all ENUM_VALUES macros used across other files defeats the purpose of the design pattern.

Is there a C++ standard way for dynamically creating these ENUM_VALUES? Is the X-macro approach flawed?

How do I create this "dynamic enumeration" design pattern in C++?

Aucun commentaire:

Enregistrer un commentaire