В таком виде это не сильно отличается от того что можно сделать
макросами в С. Ну, разве что, более строгая проверка типов.
Например, метод Toggle. inline static void Toggle() noexcept(true) {
static_assert((kType == Type::Output), "This gpio not output, check 'Type' field");
GPIO_TypeDef* regs { reinterpret_cast<GPIO_TypeDef*>(kPort) };
regs->ODR ^= kOdrMask;
}
Что нового он нам принёс? Неатомарный доступ? А на этом контроллере от него можно избавиться и дополнительно оптимизировать.
template<uint32_t PM=PinsMask>
static inline void toggle()
{
if constexpr (PM == 0xFFFF)
base()->ODR = ~base()->ODR;
else if constexpr (PM == 0x00FF)
*pVU8(&base()->ODR) = ~*pVU8(&base()->ODR);
else if constexpr (PM == 0xFF00)
*(pVU8(&base()->ODR) + 1) = ~*(pVU8(&base()->ODR) + 1);
else if constexpr (std::popcount(PM)==1)
{ if (base()->ODR & PM) clear(); else set(); }
else
base()->BSRR = (PM << 16) | (~base()->ODR & PM);
}
template<uint32_t PM=PinsMask>
static inline void set()
{
if constexpr((PM & 0xFF)==0)
*(pVU8(&base()->BSRR)+1) = PM>>8;
else
base()->BSRR = PM;
}
template<uint32_t PM=PinsMask>
static inline void clear()
{
if constexpr (PM == 0xFFFF)
base()->ODR = 0;
else if constexpr (PM == 0x00FF)
*pVU8(&base()->ODR) = 0;
else if constexpr (PM == 0xFF00)
*(pVU8(&base()->ODR) + 1) = 0;
else if constexpr((PM & 0xFF)==0)
*(pVU8(&base()->BSRR)+3) = PM>>8;
else
*(pVU16(&base()->BSRR)+1) = PM;
}