使用几种不同的数字类型查找 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;
}
}
(当然,我的项目不止a
和b
,我省略了具体的UI绘图代码,因为它不相关)
建议的解决方案
现在,我想去掉这些 switch 语句,因为它们是多余的;我必须在枚举中重复一次选项列表,在将其绘制到显示器的代码中再次重复,最后在调整值的代码中再次重复。
我考虑过使用类似于这些变量的指针(或引用)数组的方法:
double* configPars[] = {
&a,
&b,
}
然后我可以简单地将其用作 table 的查找 print/adjust:
的正确变量
void adjustConfigPar(delta) {
configPars[currentPar] += delta;
}
问题
这里的问题是我要print/adjust的这些变量并不都是同一种类型。有些是 double
s,有些是 uint8_t
s,有些是 uint16_t
s。但是,它们都是数字类型,我想对它们做的操作都是一样的: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;
}
}
};
背景
对于嵌入式项目的 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;
}
}
(当然,我的项目不止a
和b
,我省略了具体的UI绘图代码,因为它不相关)
建议的解决方案
现在,我想去掉这些 switch 语句,因为它们是多余的;我必须在枚举中重复一次选项列表,在将其绘制到显示器的代码中再次重复,最后在调整值的代码中再次重复。
我考虑过使用类似于这些变量的指针(或引用)数组的方法:
double* configPars[] = {
&a,
&b,
}
然后我可以简单地将其用作 table 的查找 print/adjust:
的正确变量void adjustConfigPar(delta) {
configPars[currentPar] += delta;
}
问题
这里的问题是我要print/adjust的这些变量并不都是同一种类型。有些是 double
s,有些是 uint8_t
s,有些是 uint16_t
s。但是,它们都是数字类型,我想对它们做的操作都是一样的: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;
}
}
};