我有一个枚举列表,定义如下:
enum PinEnum {
kPinInvalid,
kPinA0,
kPinA1,
kPinB0,
kPinB1,
kPinC0,
kPinC1,
}
Run Code Online (Sandbox Code Playgroud)
这些枚举中的每一个都需要与另外两个值相关联,即端口和引脚号.目前,我通过运行时函数访问这些:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
特别是,我这样做是因为我不希望大型查找表在运行时占用RAM(代码大小不是问题).
有没有办法使用编译时查找表,constexpr函数或模板构造来执行此操作,以便语句PinGetPin(kPinA0)和PinGetPort(kPinA0)每个语句优化为单个值,而不必经历冗长的函数调用和case语句?这些函数的参数将始终为类型const PinEnum,其值在编译时已知.
例如,典型的使用场景如下:
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
...
}
Run Code Online (Sandbox Code Playgroud)
C++ 11答案很好.
虽然编译时查找表还有其他答案,但我没有看到直接应用于此案例的答案.它们要么需要字符串递归,要么实际计算并存储一个查找表(如果没有别的办法,这可能最终会出现).
使用模板结构将枚举作为参数,模板特化和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, "");
}
Run Code Online (Sandbox Code Playgroud)
在C++ 14中,switch由于轻松的constexpr限制,您的功能可能是constexpr .
做一张桌子:
template<class...>struct types {};
template<class lhs, class rhs>struct e{};
template<class types, class lhs>
struct find{};
template<class types, class lhs>
using find_t=typename find<types,lhs>::type;
template<class T0, class R0, class...Ts>
struct find< types<e<T0,R0>,Ts...>, T0>{
using type=R0;
};
template<class T0, class R0, class...Ts, class lhs>
struct find< types<e<T0,R0>,Ts...>, lhs>:
find< types<Ts...>, lhs >
{};
Run Code Online (Sandbox Code Playgroud)
使用:
template<PinEnum e>
using PinEnum_t = std::integral_constant<PinEnum, e>;
template<uint16_t i>
using uint16 = std::integral_constant<uint16_t, i>;
using PinGetPin_t = types<
e<PinEnum_t<kPinA0>, uint16<GPIOA>>,
e<PinEnum_t<kPinA1>, uint16<GPIOA>>,
// ...
e<PinEnum_t<kPinC1>, uint16<GPIOC>>
>;
static_assert( find_t<PinGetPin_t, PinEnum_t<kPinA0>>{}==GPIOA, "oops");
Run Code Online (Sandbox Code Playgroud)
尝试访问上述系统中的无效引脚会导致编译时错误.
实例.
我把所有东西都放在了类型的土地上,并且一对一的地图.多对一地图,或没有PinEnum_t包装等,也是可能的.
| 归档时间: |
|
| 查看次数: |
2371 次 |
| 最近记录: |