【问题标题】:Lookup table with several different numeric types?具有几种不同数字类型的查找表?
【发布时间】:2021-08-20 14:36:08
【问题描述】:

背景

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

目前,在我的 UI 代码中,我有一个包含可能值的枚举,我使用 switch 语句来查找当前选定的一个并显示/编辑它:

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,
}

然后我可以简单地将其用作正确变量的查找表来打印/调整:

void adjustConfigPar(delta) {
    configPars[currentPar] += delta;
}

问题

这里的问题是我要打印/调整的这些变量并不都是同一类型。有些是doubles,有些是uint8_ts,有些是uint16_ts。但是,它们都是数字类型,我想对它们做的操作都是一样的:递增/递减,然后打印出来。

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

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

我正在这里开发一个微控制器,因此我无法访问完整的标准库,例如标准::变体。

【问题讨论】:

  • 我们在说多少个参数,是否有多个相同类型的参数?

标签: c++ embedded


【解决方案1】:

我想这就是你的意思

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
        /* ... */;
}

【讨论】:

  • 仅供参考,请勿在符号名称中使用前导下划线。前导下划线是为编译器保留的,您不想干扰编译器符号。
  • 在这种情况下,switch/case 语句可能比if-else-if 阶梯更具可读性。
  • 我建议使用enum class 而不是int 作为类型代码。 int 的值范围很广,包括一些您不想要的值。
  • 谢谢,这为我指明了正确的方向!我发布了一个稍微修改过的解决方案作为答案,它封装了类中的详细信息。
【解决方案2】:

受到@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;
        }
    }
};

【讨论】:

    猜你喜欢
    • 2015-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-09
    • 1970-01-01
    • 2019-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多