是否可以使作用域枚举("enum class")在上下文中可转换为布尔值?
Is it possible to make a scoped enumeration ("enum class") contextually convertible to bool?
假设我有
enum class Flags : std::uint16_t
{
None = 0,
A = 0x0001,
B = 0x0002,
C = 0x0004
}
inline Flags operator|(Flags lhs, Flags rhs)
{
return static_cast<Flags>(static_cast<std::uint16_t>(lhs) | static_cast<std::uint16_t>(rhs));
}
inline Flags operator&(Flags lhs, Flags rhs)
{
return static_cast<Flags>(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;
}
是否有可能使enum类在上下文中可转换为bool以允许某人执行
Flags f = /* ... */;
if (f & Flags::A) {
// Do A things
}
我不认为您可以为bool
提供转换操作符,因为没有该类的实际实例,但是您可以重载其他操作符。自然的是operator!
:
bool operator!(Flags f) {
return f == Flags::None;
}
那么你的程序会做:
if (!!(f & Flags::A)) {
这确实是不自然的,但对于其他人来说,这并不会让人感到可怕的惊讶(至于它的意思,他们可能会对双重否定感到困惑)。
或者,您可以将该操作实现为命名函数,以使其更具可读性:
bool test(Flag f, Flag mask) {
return !!(f & mask);
}
if (test(f,Flags::A)) { …
那么,如果你真的想要隐式转换,为什么要首先使用enum类呢?
虽然不能单独使用强类型枚举完成此操作,但可以将枚举类型和转换封装在类中,以获得与您所寻找的行为相似的行为。将它们组合在一起确实需要更多的努力,但不会太麻烦(除非您要处理数十个枚举基位标志)。在这种情况下,基于模板的解决方案可能是可取的。
通过将封装在一个类中,您可以获得执行问题中详细操作所需的所有转换操作符。这些转换是双向的,当在命名空间范围内与操作符结合时,提供(我希望)您想要实现的行为。
代码:
#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
)。
相关文章:
- 隐式可转换参数,但属于引用类型
- 在sfml中获取可转换的边界框
- 从c++11 time_t创建一个可转换为.net DateTime的字符串
- 包含可变参数包的第一个可转换类型的别名的结构
- 为什么类型可转换性C++不传递
- std :: iS_constructiblinsibles与参数可转换为参数的参数
- 如果模板值可转换为布尔值,则在编译时禁用类方法
- 基于上下文的转换将在果酱SDK中记住手段
- 类中参数的可变可转换检查
- 未知类方法回调,它接受 0 个参数并返回可转换为 int 的类型
- 为可转换为指针的迭代器专门化一个类
- initializer_list<T>不能转换为 initializer_list<U>,但 T 可转换为 U
- 继承自SFML中的可转换和可绘制
- 如果加法表达式的第一个操作数可转换为指针和整数,则选择哪个转换
- 在c++中检查运行时的可转换性
- 对于可转换类型,设计比循环依赖项更好
- 使用隐式可转换对象调用move重载函数时的编译错误
- 当模板类is_可转换为已知类型时,特化函子
- 是否可以使作用域枚举("enum class")在上下文中可转换为布尔值?
- 将类型转换扩展到可转换类型的对/元组