模板constexpr方法

时间:2015-07-10 10:16:13

标签: templates c++11 recursion variadic enum-class

我的微控制器项目中有以下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作为模板参数。然后,编译器将对所有这些进行OR运算,并将每个调用替换为常量值。对于微控制器,这是理想的,因为它在分配寄存器之前不必进行OR操作。

在某些情况下,我想使用下面的枚举类作为值:

enum class gpiopin : std::uint32_t {
    p0 = GPIO_IDR_IDR_0, // 0x00000001
    ...
    p14 = GPIO_IDR_IDR_14, // 0x00004000
    p15 = GPIO_IDR_IDR_15 // 0x00008000
};

由于我有多个这些枚举类,我正在寻找在上面的​​mask_or代码中使用枚举类值的通用方法。总之,我希望能够做到这一点:

SFR = mask_or<gpiopin::p1, gpiopin::p14>::value;

理想情况下,我希望mask_or&lt; ...&gt; ::值为constexpr,以保持代码大小低和速度快。

我觉得这应该是可能的,但我似乎无法使其发挥作用。任何人都可以帮助我吗?

1 个答案:

答案 0 :(得分:1)

您可以使用以下内容:

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

Live example

简单地重载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

Live example