2015-07-10 2 views
1

У меня есть следующий C++ 11 код в моем микроконтроллере проекте:Enum битмаска класса, используемая в методе шаблона constexpr

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 < ...> :: значение будет constexpr, чтобы сохранить размер кода низкой и высокой скорости.

Я чувствую, что это должно быть возможно, но я не могу заставить его работать. Может кто-нибудь мне помочь?

ответ

0

Вы могли бы использовать что-то вроде этого:

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


Это было бы намного проще для simp LY перегружать 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

+0

Оба способа работают. В итоге я использовал второй вариант (перегруженный оператор), потому что это позволило мне очистить код. Благодарю. –