使用几种不同的数字类型查找 table?

Lookup table with several different numeric types?

背景

对于嵌入式项目的 UI,必须在屏幕上显示多个变量并使其能够编辑它们。

目前,在我的 UI 代码中,我有一个包含可能值的枚举,我使用 switch 语句找到当前选择的一个并且 show/edit 它:

enum class ConfigPar {
    a,
    b,
    _last = lowValue,
};

void drawConfigScreen() {
    switch(currentPar) {
        case ConfigPar::a:
            // Draw "selected" box around a
            return;
        case ConfigPar::b:
            // Draw "selected" box around b
            return;
    }
}

void adjustConfigPar(delta) {
    switch (currentPar) {
        case ConfigPar::a:
            a += delta;
            return;
        case ConfigPar::b:
            b += delta;
            return;
    }
}

(当然,我的项目不止ab,我省略了具体的UI绘图代码,因为它不相关)

建议的解决方案

现在,我想去掉这些 switch 语句,因为它们是多余的;我必须在枚举中重复一次选项列表,在将其绘制到显示器的代码中再次重复,最后在调整值的代码中再次重复。

我考虑过使用类似于这些变量的指针(或引用)数组的方法:

double* configPars[] = {
    &a,
    &b,
}

然后我可以简单地将其用作 table 的查找 print/adjust:

的正确变量
void adjustConfigPar(delta) {
    configPars[currentPar] += delta;
}

问题

这里的问题是我要print/adjust的这些变量并不都是同一种类型。有些是 doubles,有些是 uint8_ts,有些是 uint16_ts。但是,它们都是数字类型,我想对它们做的操作都是一样的:in-/de-crement它们,并打印它们。

这当然是个问题,因为数组不能包含不同类型的项。

我想过几种复杂的方法来解决这个问题,但最终它们都遇到了同样的问题:我需要某种异构容器。

我在这里开发微控制器,所以我无法访问完整的标准库,例如std::variant.

我想这就是你的意思

struct _Var{
    int i_type; //  macros TYPE_INT or TYPE_FLOAT etc
    
    union{
        int int_value;
        float float_value;
    };
};

_Var configPars[n_size];

void adjustConfigPar(int int_delta, float float_delta)
{
    _Var*curVar =   &configPars[currentPar];
    
    if(curVar->i_type==TYPE_INT)
        curVar->int_value   +=  int_delta;
    else if(curVar->i_type==TYPE_FLOAT)
        curVar->float_value +=  float_delta;
    else
        /* ... */;
}

受@Errorist 回答的启发,我得到了这个:

class ConfigPar {
    enum class ConfigParType {
        ui8,
        ui16,
        d,
    };
public:
    // The nested struct is in order to have an overloaded constructor for the type and the union, but avoid
    // having to strcopy the label
    struct Var {
        const ConfigParType type;
        union {
            uint8_t * const ui8;
            uint16_t * const ui16;
            double * const d;
        };

        Var(uint8_t *par) : type(ConfigParType::ui16), ui8(par) {}
        Var(uint16_t *par) : type(ConfigParType::ui16), ui16(par) {}
        Var(double *par) : type(ConfigParType::d), d(par) {}
    } var;

    char label[10];

    void adjust(int8_t delta) const {
        switch (var.type) {
            case ConfigParType::ui8:
                *var.ui8 += delta;
                return;
            case ConfigParType::ui16:
                *var.ui16 += delta;
                return;
            case ConfigParType::d:
                *var.d += static_cast<double>(delta) / 100;
                return;
        }
    }
};