尽管您无法单独使用强类型枚举来完成此操作,但您可以将枚举类型和转换封装在一个类中以获得与您正在寻找的行为相似的行为。将它放在一起确实需要更多的努力,但不会很麻烦(除非你正在做几十个枚举基本标志。在这种情况下,基于模板的解决方案可能是可取的。
通过将其封装在一个类中,您可以获得执行问题中详述的操作所需的所有必要转换运算符。这些转换是双向的,当与命名空间范围内的运算符结合使用时,可以提供(我希望)您试图实现的行为。
编码:
#include <cstdint>
class Flags
{
enum class Enum : std::uint16_t
{
EMPTY = 0, FLAG1 = 1, FLAG2 = 2, FLAG3 = 4, FLAG4 = 8
};
public:
// Default constructor. At least you'll have default initialization.
Flags() : value_(EMPTY) {}
// Basic copy-ctor
Flags(const Flags& value) : value_(value.value_) {}
// Conversion-ctor allowing implicit conversions. This allows the
// non-member operators to work.
Flags(Enum value) : value_(value) {}
// We want to be able to expose and use the strongly typed enum.
operator Enum() const
{
return value_;
}
// In order to simplify the manipulation of the enum values we
// provide an explicit conversion to the underlying type.
explicit operator std::uint16_t() const
{
return static_cast<std::uint16_t>(value_);
}
// Here's your magical bool conversion.
explicit operator bool() const
{
return value_ != EMPTY;
}
// Let's make some friends so Enum can continue to be a hermit.
friend inline Flags operator|(Flags::Enum lhs, Flags::Enum rhs);
friend inline Flags operator&(Flags lhs, Flags rhs);
// As a convenience we declare the enumeration values here. This allows
// scoping similar to the typed enums.
static const Enum EMPTY = Enum::EMPTY;
static const Enum FLAG1 = Enum::FLAG1;
static const Enum FLAG2 = Enum::FLAG2;
static const Enum FLAG3 = Enum::FLAG3;
static const Enum FLAG4 = Enum::FLAG4;
private:
Enum value_;
};
inline Flags operator|(Flags::Enum lhs, Flags::Enum rhs)
{
return static_cast<Flags::Enum>(
static_cast<std::uint16_t>(lhs)
| static_cast<std::uint16_t>(rhs));
}
inline Flags operator&(Flags lhs, Flags rhs)
{
return static_cast<Flags::Enum>(
static_cast<std::uint16_t>(lhs)
& static_cast<std::uint16_t>(rhs));
}
inline Flags operator|=(Flags& lhs, Flags rhs)
{
return lhs = lhs | rhs;
}
inline Flags operator&=(Flags& lhs, Flags rhs)
{
return lhs = lhs & rhs;
}
void Func(Flags)
{
// do something really cool here
}
int main()
{
Flags f;
// equality
if (f) {}
if (!f) {}
// operations and more equality
f |= Flags::FLAG1;
if (f & Flags::FLAG1) {}
f &= Flags::FLAG1;
// Call a function after doing some ops on the plain enum values
Func(Flags::FLAG1 | Flags::FLAG2);
}
我看到的一个缺点是它不能很好地处理与枚举相关的类型特征(即std::underlying_type
)。