【问题标题】:Enum class bitmasks used in template constexpr method模板 constexpr 方法中使用的枚举类位掩码
【发布时间】:2015-07-10 10:16:13
【问题描述】:

我的微控制器项目中有以下 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<...>::value 为 constexpr 以保持代码大小低且速度快。

我觉得这应该是可能的,但我似乎无法让它发挥作用。谁能帮帮我?

【问题讨论】:

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


    【解决方案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

    【讨论】:

    • 两种方式都有效。我最终使用了第二个选项(重载运算符),因为它允许我清理代码。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多