#pragma once #include #include // Wrapper around enum that can have multiple values (or none) set at once. template struct MultiEnum { using StorageType = StorageTypeT; using EnumType = EnumTypeT; MultiEnum() = default; template ...>>> constexpr explicit MultiEnum(EnumValues ... v) : MultiEnum((toBitFlag(v) | ... | 0u)) {} template >> constexpr explicit MultiEnum(ValueType v) : bitset(v) { static_assert(std::is_unsigned_v); static_assert(std::is_unsigned_v && std::is_integral_v); } MultiEnum(const MultiEnum & other) = default; MultiEnum & operator=(const MultiEnum & other) = default; bool isSet(EnumType value) const { return bitset & toBitFlag(value); } void set(EnumType value) { bitset |= toBitFlag(value); } void unSet(EnumType value) { bitset &= ~(toBitFlag(value)); } void reset() { bitset = 0; } StorageType getValue() const { return bitset; } template >> void setValue(ValueType new_value) { // Can't set value from any enum avoid confusion static_assert(!std::is_enum_v); bitset = new_value; } bool operator==(const MultiEnum & other) const { return bitset == other.bitset; } template >> bool operator==(ValueType other) const { // Shouldn't be comparable with any enum to avoid confusion static_assert(!std::is_enum_v); return bitset == other; } template bool operator!=(U && other) const { return !(*this == other); } template >> friend bool operator==(ValueType left, MultiEnum right) { return right.operator==(left); } template >::type> friend bool operator!=(L left, MultiEnum right) { return !(right.operator==(left)); } private: StorageType bitset = 0; static constexpr StorageType toBitFlag(EnumType v) { return StorageType{1} << static_cast(v); } };