vendredi 28 août 2015

Bitwise scoped enum as a normal scoped enum

I have a bitwise enum class with bitwise operator functions defined, something like this:

enum class RegisterableComponents : unsigned int
{
    None        = 0b0000,
    Component1  = 0b0001,
    Component2  = 0b0010,
    Component3  = 0b0100
}

using T = std::underlying_type_t<RegisterableComponents>;

inline RegisterableComponents operator | (RegisterableComponents lhs, RegisterableComponents rhs)
{
    return (RegisterableComponents)(static_cast<T>(lhs) | static_cast<T>(rhs));
}

inline RegisterableComponents& operator |= (RegisterableComponents& lhs, RegisterableComponents rhs)
{
    lhs = (RegisterableComponents)(static_cast<T>(lhs) | static_cast<T>(rhs));
    return lhs;
}

inline bool any(RegisterableComponents &components)
{
    return (components == RegisterableComponents::None);
}

I also want to be able to create an array the same size as the number of components, and use these flags as indexes to said array, so I've changed the enum to store the number of shifts, perform bitshifts in the bitwise operations and require the user to use the underlying type:

enum class RegisterableComponentFlags : unsigned int
{
    Component1,     //0
    Component2,     //1
    Component3,     //2
    Max             //3
}

using RegisterableComponentType = std::underlying_type_t<RegisterableComponentFlags>;

inline RegisterableComponentType operator | (RegisterableComponentType lhs, RegisterableComponentFlags rhs)
{
    return (RegisterableComponentType)(lhs | toBitwise(rhs));
}

inline RegisterableComponentType& operator |= (RegisterableComponentType& lhs, RegisterableComponentFlags rhs)
{
    lhs = (RegisterableComponentType)(lhs | toBitwise(rhs));
    return lhs;
}

bool operator > (RegisterableComponentType lhs, RegisterableComponentFlags rhs)
{
    return (lhs > toBitwise(rhs));
}

inline bool any(RegisterableComponentType &components)
{
    return (components == 0 || components > RegisterableComponentFlags::Max);
}

template<class T>
constexpr auto toBitwise(T t) -> typename std::underlying_type<T>::type
{
    return 1 << toBaseType(t);
}

template<class T>
constexpr auto toBaseType(T t) -> typename std::underlying_type<T>::type
{
    return static_cast<typename std::underlying_type<T>::type>(t);
}

//I can now do this:
//std::array<T, toBaseType(RegisterableComponentFlags::Max)> x;
//and also use them as indexes

Performing bitshifts inside the bitwise operation functions feels hacky; I'm sure that I'm violating the whole point of scoped enums by making the user use the underlying type rather than the type of the enum; and the user has to static_cast the initial assignment. So is there a nicer way for me to achieve what I want?

Aucun commentaire:

Enregistrer un commentaire