Search code examples
c++preprocessor

How to store indicies of an array in preprocessor defines?


I am creating a VST(virtual instrument) program in cpp and I have an array of structs that represent various parameters in my program:

const FloatParam_Properties FloatParamProps[NUM_FLOAT_PARAMS] =
{
    //Frequency
    {"BaseFreq",    "Base Freq",    0.0,    20.0,   5.0,    0.6},   //0 
    {"FreqDelta",   "Freq Delta",   -20.0,  20.0,   0.0,    0.6},   //1
    ...

    //Wave
    {"OscSelect",   "Wave form",    0.0,    3.0,    0.0,    1.0},   //9

    //Master
    {"Volume",      "Volume",       0.0,    1.0,    0.1,    0.4},   //10
};

Each element in this array is a struct, when I want to access these structs I have just hardcoded the indices(e.g. doing FloatParamProps[0] to access the Base Frequency). However, I would like to use the cpp preprocessor to give these hard-coded indices a name since everything here is known at compile-time and it would be good if I didn't have to just hard-code those defines either.

What I would like to do is something like:

const FloatParam_Properties FloatParamProps[NUM_FLOAT_PARAMS] =
{
    //Frequency
    DEF_FLOAT_PARAM(BaseFreq,    "Base Freq",    0.0,    20.0,   5.0,    0.6),   //0 
    DEF_FLOAT_PARAM(FreqDelta,   "Freq Delta",   -20.0,  20.0,   0.0,    0.6),   //1
    ...

    //Wave
    DEF_FLOAT_PARAM(OscSelect,   "Wave form",    0.0,    3.0,    0.0,    1.0),   //9

    //Master
    DEF_FLOAT_PARAM(Volume,      "Volume",       0.0,    1.0,    0.1,    0.4),   //10
};

Where DEF_FLOAT_PARAM was a macro that would then take the first argument and turn that into a pre-processor define(or maybe constexpr) by using the __COUNTER__ macro. Then, if I wanted to access the first one I could do FloatParamProps[BaseFreq], for example. The issue I'm having is that you can't have a define within a macro so I can't define BaseFreq as a constant.

I also tried doing something like

#define DEF_FLOAT_PARAM(ID, Name, minVal, maxVal, defaultVal, skewFactor) P_##ID __COUNTER__ \
            {#ID, Name, minVal, maxVal, defaultVal, skewFactor}, 

and the plan here was to try and take the define outside of the macro and just type that manually like so:

const FloatParam_Properties FloatParamProps[NUM_FLOAT_PARAMS] =
{
    //Frequency
    #define DEF_FLOAT_PARAM(BaseFreq,    "Base Freq",    0.0,    20.0,   5.0,    0.6),   //0
    ... 

But the issue with that is that the pre-processor doesn't want to expand that macro when it's in-front of the define. If only I could tell it to expand the macro, it would work.

Does anyone know how I could do this?

Thanks.


Solution

  • Use x-macros:

    #define PARAMS(X) \
        X(BaseFreq,    "Base Freq",    0.0,    20.0,   5.0,    0.6) \
        X(FreqDelta,   "Freq Delta",   -20.0,  20.0,   0.0,    0.6) \
        X(OscSelect,   "Wave form",    0.0,    3.0,    0.0,    1.0)
    
    const FloatParam_Properties FloatParamProps[NUM_FLOAT_PARAMS] =
    {
        #define PARAM_STRUCT(id, ...) {#id, __VA_ARGS__},
        PARAMS(PARAM_STRUCT)
        #undef PARAM_STRUCT
    };
    
    enum Params
    {
        #define PARAM_ENUM(id, ...) id,
        PARAMS(PARAM_ENUM)
        #define PARAM_ENUM
        _count,
    };
    

    This will generate the same array you already have, and a enum with the constants matching the array indices.