枚举的编译时查找表 [英] Compile-time lookup table for enum
问题描述
我有一个枚举列表,定义如下:
I have a list of enums which are defined as follows:
enum PinEnum {
kPinInvalid,
kPinA0,
kPinA1,
kPinB0,
kPinB1,
kPinC0,
kPinC1,
}
这些枚举中的每个枚举都需要与其他两个值(端口和引脚号)相关联.目前,我正在通过运行时函数来访问这些文件:
Each of these enums needs to be associated with two other values, the port and the pin number. Currently, I'm accessing these through run-time functions:
GPIO_TypeDef * PinGetPort(const PinEnum pin) {
switch (pin) {
case kPinA0:
case kPinA1:
return GPIOA;
case kPinB0:
case kPinB1:
return GPIOB;
case kPinC0:
case kPinC1:
return GPIOC;
default:
return NULL;
}
}
uint16_t PinGetPin(const PinEnum pin) {
switch (pin) {
case kPinA0:
case kPinB0:
case kPinC0:
return GPIO_Pin_0;
case kPinA1:
case kPinB1:
case kPinC1:
return GPIO_Pin_1;
default:
return 0;
}
}
我之所以这样做,是因为我不希望大的查找表在运行时占用RAM(代码大小已不再是问题).
In particular, I'm doing this because I do not want a large lookup table to be taking up RAM at runtime (code size is much less of an issue).
是否可以使用编译时查找表, constexpr
函数或模板构造来执行此操作,从而使语句 PinGetPin(kPinA0)
和 PinGetPort(kPinA0)
分别优化为单个值,而不必经历冗长的函数调用和case语句?这些函数的参数将始终为 const PinEnum
类型,其值在编译时为已知.
Is there a way to do this using a compile-time lookup table, constexpr
function, or a template construct so that the statements PinGetPin(kPinA0)
and PinGetPort(kPinA0)
each get optimized to a single value instead of having to go through a lengthy function call and case statement? The arguments to these functions will always be of type const PinEnum
with values known at compile time.
例如,以下是典型的使用场景:
For example, a typical usage scenario is the following:
const PinEnum kPinStatus = kPinB0;
int main(int argc, char ** argv) {
...
PinGetPort(kPinStatus)->BSRRH = PinGetPin(kPinStatus);
// GPIOB->BSRRH = GPIO_Pin_0; <-- should optimize to this during compilation
...
}
C ++ 11的答案很好.
C++11 answers are fine.
尽管对于编译时查找表还有其他答案,但我没有看到一个直接适用于这种情况的答案.它们要么需要字符串递归,要么实际上是计算并存储查找表(如果没有其他方法,最终可能会找到该表).
While there are other answers out there for compile-time lookup tables, I do not see one which would directly apply to this case. They either require string recursion, or actually calculate and store a lookup table (which this may end up coming to if there's no other way).
推荐答案
使用以枚举为参数的模板结构,模板专业化和 std :: integral_constant
.
Use template structs taking enum as a parameter, template specialization, and std::integral_constant
.
#include <type_traits>
enum class pin { pin0, pin1 };
template<pin> struct lookup_port;
template<pin> struct lookup_num;
template<> struct lookup_port<pin::pin0>
: std::integral_constant<int, 0> { };
template<> struct lookup_num<pin::pin0>
: std::integral_constant<int, 520> { };
template<> struct lookup_port<pin::pin1>
: std::integral_constant<int, 22> { };
template<> struct lookup_num<pin::pin1>
: std::integral_constant<int, 5440> { };
int main()
{
static_assert(lookup_port<pin::pin0>::value == 0, "");
static_assert(lookup_port<pin::pin1>::value == 22, "");
static_assert(lookup_num<pin::pin0>::value == 520, "");
static_assert(lookup_num<pin::pin1>::value == 5440, "");
}
在C ++ 14中,由于 switch 函数可以是constexpr.rel ="noreferrer">放松的constexpr限制.
In C++14, your switch
function could be constexpr, thanks to relaxed constexpr restrictions.
这篇关于枚举的编译时查找表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!