template<typename Enum, bool IsEnum = std::is_enum<Enum>::value>
class bitflag;
template<typename Enum>
class bitflag<Enum, true>
{
public:
constexpr const static int number_of_bits = std::numeric_limits<typename std::underlying_type<Enum>::type>::digits;
constexpr bitflag() = default;
constexpr bitflag(Enum value) : bits(1 << static_cast<std::size_t>(value)) {}
constexpr bitflag(const bitflag& other) : bits(other.bits) {}
constexpr bitflag operator|(Enum value) const { bitflag result = *this; result.bits |= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator&(Enum value) const { bitflag result = *this; result.bits &= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator^(Enum value) const { bitflag result = *this; result.bits ^= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator~() const { bitflag result = *this; result.bits.flip(); return result; }
constexpr bitflag& operator|=(Enum value) { bits |= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator&=(Enum value) { bits &= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator^=(Enum value) { bits ^= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bool any() const { return bits.any(); }
constexpr bool all() const { return bits.all(); }
constexpr bool none() const { return bits.none(); }
constexpr operator bool() const { return any(); }
constexpr bool test(Enum value) const { return bits.test(1 << static_cast<std::size_t>(value)); }
constexpr void set(Enum value) { bits.set(1 << static_cast<std::size_t>(value)); }
constexpr void unset(Enum value) { bits.reset(1 << static_cast<std::size_t>(value)); }
private:
std::bitset<number_of_bits> bits;
};
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator|(Enum left, Enum right)
{
return bitflag<Enum>(left) | right;
}
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator&(Enum left, Enum right)
{
return bitflag<Enum>(left) & right;
}
template<typename Enum>
constexpr typename std::enable_if_t<std::is_enum<Enum>::value, bitflag<Enum>>::type operator^(Enum left, Enum right)
{
return bitflag<Enum>(left) ^ right;
}
template<typename Enum, bool IsEnum = std::is_enum<Enum>::value>
class bitflag;
template<typename Enum>
class bitflag<Enum, true>
{
public:
constexpr const static int number_of_bits = std::numeric_limits<typename std::underlying_type<Enum>::type>::digits;
constexpr bitflag() = default;
constexpr bitflag(Enum value) : bits(1 << static_cast<std::size_t>(value)) {}
constexpr bitflag(const bitflag& other) : bits(other.bits) {}
constexpr bitflag operator|(Enum value) const { bitflag result = *this; result.bits |= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator&(Enum value) const { bitflag result = *this; result.bits &= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator^(Enum value) const { bitflag result = *this; result.bits ^= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator~() const { bitflag result = *this; result.bits.flip(); return result; }
constexpr bitflag& operator|=(Enum value) { bits |= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator&=(Enum value) { bits &= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator^=(Enum value) { bits ^= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bool any() const { return bits.any(); }
constexpr bool all() const { return bits.all(); }
constexpr bool none() const { return bits.none(); }
constexpr operator bool() { return any(); }
constexpr bool test(Enum value) const { return bits.test(1 << static_cast<std::size_t>(value)); }
constexpr void set(Enum value) { bits.set(1 << static_cast<std::size_t>(value)); }
constexpr void unset(Enum value) { bits.reset(1 << static_cast<std::size_t>(value)); }
private:
std::bitset<number_of_bits> bits;
};
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator|(Enum left, Enum right)
{
return bitflag<Enum>(left) | right;
}
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator&(Enum left, Enum right)
{
return bitflag<Enum>(left) & right;
}
template<typename Enum>
constexpr typename std::enable_if_t<std::is_enum<Enum>::value, bitflag<Enum>>::type operator^(Enum left, Enum right)
{
return bitflag<Enum>(left) ^ right;
}
template<typename Enum, bool IsEnum = std::is_enum<Enum>::value>
class bitflag;
template<typename Enum>
class bitflag<Enum, true>
{
public:
constexpr const static int number_of_bits = std::numeric_limits<typename std::underlying_type<Enum>::type>::digits;
constexpr bitflag() = default;
constexpr bitflag(Enum value) : bits(1 << static_cast<std::size_t>(value)) {}
constexpr bitflag(const bitflag& other) : bits(other.bits) {}
constexpr bitflag operator|(Enum value) const { bitflag result = *this; result.bits |= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator&(Enum value) const { bitflag result = *this; result.bits &= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator^(Enum value) const { bitflag result = *this; result.bits ^= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator~() const { bitflag result = *this; result.bits.flip(); return result; }
constexpr bitflag& operator|=(Enum value) { bits |= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator&=(Enum value) { bits &= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator^=(Enum value) { bits ^= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bool any() const { return bits.any(); }
constexpr bool all() const { return bits.all(); }
constexpr bool none() const { return bits.none(); }
constexpr operator bool() const { return any(); }
constexpr bool test(Enum value) const { return bits.test(1 << static_cast<std::size_t>(value)); }
constexpr void set(Enum value) { bits.set(1 << static_cast<std::size_t>(value)); }
constexpr void unset(Enum value) { bits.reset(1 << static_cast<std::size_t>(value)); }
private:
std::bitset<number_of_bits> bits;
};
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator|(Enum left, Enum right)
{
return bitflag<Enum>(left) | right;
}
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator&(Enum left, Enum right)
{
return bitflag<Enum>(left) & right;
}
template<typename Enum>
constexpr typename std::enable_if_t<std::is_enum<Enum>::value, bitflag<Enum>>::type operator^(Enum left, Enum right)
{
return bitflag<Enum>(left) ^ right;
}
template<typename Enum, bool IsEnum = std::size_t number_of_bitsis_enum<Enum>::value>
class =bitflag;
template<typename 32>Enum>
class bitflagbitflag<Enum, true>
{
public:
constexpr const static int number_of_bits = std::numeric_limits<typename std::underlying_type<Enum>::type>::digits;
constexpr bitflag() = default;
constexpr bitflag(Enum value) : bits(1 << static_cast<std::size_t>(value)) {}
constexpr bitflag(const bitflag& other) : bits(other.bits) {}
constexpr bitflag operator|(Enum value) const { bitflag result = *this; result.bits |= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator&(Enum value) const { bitflag result = *this; result.bits &= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator^(Enum value) const { bitflag result = *this; result.bits ^= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator~() const { bitflag result = *this; result.bits.flip(); return result; }
constexpr bitflag& operator|=(Enum value) { bits |= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator&=(Enum value) { bits &= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator^=(Enum value) { bits ^= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bool any() const { return bits.any(); }
constexpr bool all() const { return bits.all(); }
constexpr bool none() const { return bits.none(); }
constexpr operator bool() { return any(); }
constexpr bool test(Enum value) const { return bits.test(1 << static_cast<std::size_t>(value)); }
constexpr void set(Enum value) { bits.set(1 << static_cast<std::size_t>(value)); }
constexpr void unset(Enum value) { bits.reset(1 << static_cast<std::size_t>(value)); }
private:
std::bitset<number_of_bits> bits;
};
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator|(Enum left, Enum right)
{
return bitflag<Enum>(left) | right;
}
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator&(Enum left, Enum right)
{
return bitflag<Enum>(left) & right;
}
template<typename Enum>
constexpr typename std::enable_if_t<std::is_enum<Enum>::value, bitflag<Enum>>::type operator^(Enum left, Enum right)
{
return bitflag<Enum>(left) ^ right;
}
NoteNote the number_of_bits can unfortunately not be filled in by the compiler, as C++ doesn't have any way to do introspect the possible values of an enumeration.
Edit:
Actually I stand corrected, it is possible to get the compiler fill number_of_bits can unfortunately not be filled in by the compiler, as C++ doesn't have any way to do introspect the possible values of an enumerationfor you.
Note this can handle (wildly inefficiently) a non-continuous enum value range. Let's just say it's not a good idea to use the above with an enum like this or madness will ensue:
template<typename Enum, std::size_t number_of_bits = 32>
class bitflag
{
public:
constexpr bitflag() = default;
constexpr bitflag(Enum value) : bits(1 << static_cast<std::size_t>(value)) {}
constexpr bitflag(const bitflag& other) : bits(other.bits) {}
constexpr bitflag operator|(Enum value) const { bitflag result = *this; result.bits |= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator&(Enum value) const { bitflag result = *this; result.bits &= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator^(Enum value) const { bitflag result = *this; result.bits ^= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator~() const { bitflag result = *this; result.bits.flip(); return result; }
constexpr bitflag& operator|=(Enum value) { bits |= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator&=(Enum value) { bits &= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator^=(Enum value) { bits ^= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bool any() const { return bits.any(); }
constexpr bool all() const { return bits.all(); }
constexpr bool none() const { return bits.none(); }
constexpr operator bool() { return any(); }
constexpr bool test(Enum value) const { return bits.test(1 << static_cast<std::size_t>(value)); }
constexpr void set(Enum value) { bits.set(1 << static_cast<std::size_t>(value)); }
constexpr void unset(Enum value) { bits.reset(1 << static_cast<std::size_t>(value)); }
private:
std::bitset<number_of_bits> bits;
};
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator|(Enum left, Enum right)
{
return bitflag<Enum>(left) | right;
}
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator&(Enum left, Enum right)
{
return bitflag<Enum>(left) & right;
}
template<typename Enum>
constexpr typename std::enable_if_t<std::is_enum<Enum>::value, bitflag<Enum>>::type operator^(Enum left, Enum right)
{
return bitflag<Enum>(left) ^ right;
}
Note the number_of_bits can unfortunately not be filled in by the compiler, as C++ doesn't have any way to do introspect the possible values of an enumeration. Note this can handle (wildly inefficiently) a non-continuous enum value range. Let's just say it's not a good idea to use the above with an enum like this or madness will ensue:
template<typename Enum, bool IsEnum = std::is_enum<Enum>::value>
class bitflag;
template<typename Enum>
class bitflag<Enum, true>
{
public:
constexpr const static int number_of_bits = std::numeric_limits<typename std::underlying_type<Enum>::type>::digits;
constexpr bitflag() = default;
constexpr bitflag(Enum value) : bits(1 << static_cast<std::size_t>(value)) {}
constexpr bitflag(const bitflag& other) : bits(other.bits) {}
constexpr bitflag operator|(Enum value) const { bitflag result = *this; result.bits |= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator&(Enum value) const { bitflag result = *this; result.bits &= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator^(Enum value) const { bitflag result = *this; result.bits ^= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator~() const { bitflag result = *this; result.bits.flip(); return result; }
constexpr bitflag& operator|=(Enum value) { bits |= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator&=(Enum value) { bits &= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator^=(Enum value) { bits ^= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bool any() const { return bits.any(); }
constexpr bool all() const { return bits.all(); }
constexpr bool none() const { return bits.none(); }
constexpr operator bool() { return any(); }
constexpr bool test(Enum value) const { return bits.test(1 << static_cast<std::size_t>(value)); }
constexpr void set(Enum value) { bits.set(1 << static_cast<std::size_t>(value)); }
constexpr void unset(Enum value) { bits.reset(1 << static_cast<std::size_t>(value)); }
private:
std::bitset<number_of_bits> bits;
};
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator|(Enum left, Enum right)
{
return bitflag<Enum>(left) | right;
}
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator&(Enum left, Enum right)
{
return bitflag<Enum>(left) & right;
}
template<typename Enum>
constexpr typename std::enable_if_t<std::is_enum<Enum>::value, bitflag<Enum>>::type operator^(Enum left, Enum right)
{
return bitflag<Enum>(left) ^ right;
}
Note the number_of_bits can unfortunately not be filled in by the compiler, as C++ doesn't have any way to do introspect the possible values of an enumeration.
Edit:
Actually I stand corrected, it is possible to get the compiler fill number_of_bits for you.
Note this can handle (wildly inefficiently) a non-continuous enum value range. Let's just say it's not a good idea to use the above with an enum like this or madness will ensue:
You can define type-safe enum flags in C++11 by using std::enable_if. This is a rudimentary implementation that may be missing some things:
template<typename Enum, std::size_t number_of_bits = 32>
class bitflag
{
public:
constexpr bitflag() = default;
constexpr bitflag(Enum value) : bits(1 << static_cast<std::size_t>(value)) {}
constexpr bitflag(const bitflag& other) : bits(other.bits) {}
constexpr bitflag operator|(Enum value) const { bitflag result = *this; result.bits |= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator&(Enum value) const { bitflag result = *this; result.bits &= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator^(Enum value) const { bitflag result = *this; result.bits ^= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator~() const { bitflag result = *this; result.bits.flip(); return result; }
constexpr bitflag& operator|=(Enum value) { bits |= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator&=(Enum value) { bits &= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator^=(Enum value) { bits ^= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bool any() const { return bits.any(); }
constexpr bool all() const { return bits.all(); }
constexpr bool none() const { return bits.none(); }
constexpr operator bool() { return any(); }
constexpr bool test(Enum value) const { return bits.test(1 << static_cast<std::size_t>(value)); }
constexpr void set(Enum value) { bits.set(1 << static_cast<std::size_t>(value)); }
constexpr void unset(Enum value) { bits.reset(1 << static_cast<std::size_t>(value)); }
private:
std::bitset<number_of_bits> bits;
};
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator|(Enum left, Enum right)
{
return bitflag<Enum>(left) | right;
}
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator&(Enum left, Enum right)
{
return bitflag<Enum>(left) & right;
}
template<typename Enum>
constexpr typename std::enable_if_t<std::is_enum<Enum>::value, bitflag<Enum>>::type operator^(Enum left, Enum right)
{
return bitflag<Enum>(left) ^ right;
}
Note the number_of_bits can unfortunately not be filled in by the compiler, as C++ doesn't have any way to do introspect the possible values of an enumeration. Note this can handle (wildly inefficiently) a non-continuous enum value range. Let's just say it's not a good idea to use the above with an enum like this or madness will ensue:
enum class wild_range { start = 0, end = 999999999 };
But all things considered this is a quite usable solution in the end. Doesn't need any user-side bitfiddling, is type-safe and within its bounds, as efficient as it gets (I'm leaning strongly on std::bitset implementation quality here ;)).