Здравствуйте, Marty, Вы писали:
M>А вот это видимо то, почему я сразу так не сделал, и просто забыл
M>А есть какие-нибудь варианты?
Вариант через класс и на шаблонах, а не на макросах.
Я делал так
#pragma once
#include <initializer_list>
#include <type_traits>
namespace foo
{
template<typename BitEnum>
class Flags;
}
/// A class that handles bitmasked enum (preferrably enum class) in a way that it keeps type safety, but
/// provides simplicity and convenience of raw integers.
///
/// \details The enum must consist from bit-masked values, e.g.
/// \code{.cpp}
/// enum class SomeFlags
/// {
/// Flag0 = 0b0001,
/// Flag1 = 0b0010,
/// Flag2 = 0b0100,
/// Flag3 = 0b1000,
/// };
/// \endcode
/// Although multi-bit enum members are allowed and just represent shorthand for common combinations, a care
/// should be taken not to treat them as individual values.
template<typename BitEnum>
class foo::Flags
{
using UnderlyingType = std::underlying_type_t<BitEnum>;
template<typename T1, typename... REST>
constexpr UnderlyingType makeMask(T1 first, REST... rest) const
{
static_assert((std::is_same_v<T1, BitEnum> && ... && std::is_same_v<REST, BitEnum>), "Arguments must be of enum type");
return (UnderlyingType(first) | ... | UnderlyingType(rest));
}
public:
constexpr Flags() = default;
/// Constructs a flag set by combining/disjuncting its' arguments.
template<typename T1, typename... REST>
constexpr Flags(T1 first, REST... rest)
: m_flags(makeMask(first, rest...))
{
}
/// Constructs a flag set by combining/disjuncting flags in passed initializer list.
constexpr Flags(std::initializer_list<BitEnum> list)
{
for (auto flag : list)
m_flags |= UnderlyingType(flag);
}
/// Tells whether any of specified flags are set.
template<typename T1, typename... REST>
constexpr bool any(T1 first, REST... rest) const
{
return bool(m_flags & makeMask(first, rest...));
}
/// Tells whether all of specified flags are set.
template<typename T1, typename... REST>
constexpr bool all(T1 first, REST... rest) const
{
const auto mask = makeMask(first, rest...);
return (m_flags & mask) == mask;
}
/// Tells whether none of specified flags are set.
template<typename T1, typename... REST>
constexpr bool none(T1 first, REST... rest) const
{
const auto mask = makeMask(first, rest...);
return !(m_flags & mask);
}
/// Sets specified flags.
template<typename T1, typename... REST>
constexpr Flags& set(T1 first, REST... rest)
{
m_flags |= makeMask(first, rest...);
return *this;
}
/// Unsets specified flags.
template<typename T1, typename... REST>
constexpr Flags& reset(T1 first, REST... rest)
{
m_flags &= ~makeMask(first, rest...);
return *this;
}
/// Unsets all flags.
void clear()
{
m_flags = 0;
}
constexpr explicit operator bool() const
{
return m_flags != 0;
}
constexpr bool operator!() const
{
return m_flags == 0;
}
constexpr operator BitEnum() const
{
return BitEnum(m_flags);
}
constexpr Flags operator&(Flags r)
{
return Flags{BitEnum(m_flags & r.m_flags)};
}
constexpr friend Flags operator&(BitEnum l, Flags r)
{
return Flags(l) & r;
}
constexpr Flags operator|(Flags r)
{
return Flags{BitEnum(m_flags | r.m_flags)};
}
constexpr friend Flags operator|(BitEnum l, Flags r)
{
return Flags(l) | r;
}
constexpr Flags& operator&=(Flags r)
{
m_flags &= r.m_flags;
return *this;
}
constexpr Flags& operator|=(Flags r)
{
m_flags |= r.m_flags;
return *this;
}
private:
UnderlyingType m_flags = 0;
};