模板 constexpr 方法中使用的枚举 class 个位掩码
Enum class bitmasks used in template constexpr method
我的微控制器项目中有以下 C++11 代码:
template<std::uint32_t... I>
struct mask_or;
template<>
struct mask_or<> {
static constexpr std::uint32_t value = 0;
};
template<std::uint32_t first, std::uint32_t... rest>
struct mask_or<first, rest...> {
static constexpr std::uint32_t value = first | mask_or<rest...>::value;
};
这很好用,并且允许我传递可变数量的 uint32_t 作为模板参数。然后编译器将对所有这些进行或运算,并将每个调用替换为一个常量值。对于微控制器来说,这是理想的,因为它不必在分配给寄存器之前进行或运算。
对于某些情况,我想使用如下所示的枚举 class 作为值:
enum class gpiopin : std::uint32_t {
p0 = GPIO_IDR_IDR_0, // 0x00000001
...
p14 = GPIO_IDR_IDR_14, // 0x00004000
p15 = GPIO_IDR_IDR_15 // 0x00008000
};
由于我有多个这样的枚举 classes,我正在寻找一种在上述 mask_or 代码中使用枚举 class 值的通用方法。总之,我希望能够做到这一点:
SFR = mask_or<gpiopin::p1, gpiopin::p14>::value;
理想情况下,我希望 mask_or<...>::value 是 constexpr 以保持低代码大小和高速度。
我觉得这应该是可能的,但我似乎无法让它发挥作用。谁能帮帮我?
你可以使用这样的东西:
template<typename E, E... I>
struct mask_or;
template<typename E>
struct mask_or<E> {
static constexpr E value = E(0);
};
template<typename E, E first, E... rest>
struct mask_or<E, first, rest...> {
using UT = typename std::underlying_type<E>::type;
static constexpr E value = E(UT(first) | UT(mask_or<E, rest...>::value));
};
但这仍然不是最佳选择,因为您现在需要将类型添加为第一个参数:
mask_or<gpiopin, gpiopin::p0, gpiopin::p14>::value
简单地重载 operator|
:
会 容易得多
template<typename> struct is_bitmask : std::false_type {};
template<typename E>
constexpr
typename std::enable_if<is_bitmask<E>::value, E>::type
operator|( const E lhs, const E rhs )
{
using UT = typename std::underlying_type<E>::type;
return E(UT(lhs) | UT(rhs));
}
并使用
为操作员注册您的类型
template<> struct is_bitmask<gpiopin> : std::true_type {};
有了这个,你就可以使用
gpiopin::p0 | gpiopin::p14
我的微控制器项目中有以下 C++11 代码:
template<std::uint32_t... I>
struct mask_or;
template<>
struct mask_or<> {
static constexpr std::uint32_t value = 0;
};
template<std::uint32_t first, std::uint32_t... rest>
struct mask_or<first, rest...> {
static constexpr std::uint32_t value = first | mask_or<rest...>::value;
};
这很好用,并且允许我传递可变数量的 uint32_t 作为模板参数。然后编译器将对所有这些进行或运算,并将每个调用替换为一个常量值。对于微控制器来说,这是理想的,因为它不必在分配给寄存器之前进行或运算。
对于某些情况,我想使用如下所示的枚举 class 作为值:
enum class gpiopin : std::uint32_t {
p0 = GPIO_IDR_IDR_0, // 0x00000001
...
p14 = GPIO_IDR_IDR_14, // 0x00004000
p15 = GPIO_IDR_IDR_15 // 0x00008000
};
由于我有多个这样的枚举 classes,我正在寻找一种在上述 mask_or 代码中使用枚举 class 值的通用方法。总之,我希望能够做到这一点:
SFR = mask_or<gpiopin::p1, gpiopin::p14>::value;
理想情况下,我希望 mask_or<...>::value 是 constexpr 以保持低代码大小和高速度。
我觉得这应该是可能的,但我似乎无法让它发挥作用。谁能帮帮我?
你可以使用这样的东西:
template<typename E, E... I>
struct mask_or;
template<typename E>
struct mask_or<E> {
static constexpr E value = E(0);
};
template<typename E, E first, E... rest>
struct mask_or<E, first, rest...> {
using UT = typename std::underlying_type<E>::type;
static constexpr E value = E(UT(first) | UT(mask_or<E, rest...>::value));
};
但这仍然不是最佳选择,因为您现在需要将类型添加为第一个参数:
mask_or<gpiopin, gpiopin::p0, gpiopin::p14>::value
简单地重载 operator|
:
template<typename> struct is_bitmask : std::false_type {};
template<typename E>
constexpr
typename std::enable_if<is_bitmask<E>::value, E>::type
operator|( const E lhs, const E rhs )
{
using UT = typename std::underlying_type<E>::type;
return E(UT(lhs) | UT(rhs));
}
并使用
为操作员注册您的类型template<> struct is_bitmask<gpiopin> : std::true_type {};
有了这个,你就可以使用
gpiopin::p0 | gpiopin::p14