使用enum类的符合C++11标准的位掩码
C++11 standard conformant bitmasks using enum class
是否可以使用enum类实现符合标准(如n3242草案17.5.5.2.1.3中所述)类型的安全位掩码?根据我的理解,如果类型T支持|,&,^,~,|=,则它是一个位掩码&=和^=运算符,并且如果(l&r)其中l和r是T类型,则可以进一步执行。列表中缺少运算符!=和==并且为了允许排序,可能还希望重载<。
让操作符工作只是烦人的样板代码,但我不知道如何做if(l&r)。至少以下内容不使用GCC进行编译(除了极其危险,因为它允许错误地隐式转换为int):
enum class Foo{
operator bool(){
return (unsigned)*this;
}
};
编辑:我现在确定了枚举类不能有成员。如果(l&r)如何处理的实际问题仍然存在。
我想你可以。。。您将不得不为bitmasky事物添加运算符。我在这里没有这么做,但你可以很容易地重载任何关系运算符。
/**
*
*/
// NOTE: I changed to a more descriptive and consistent name
// This needs to be a real bitmask type.
enum class file_permissions : int
{
no_perms = 0,
owner_read = 0400,
owner_write = 0200,
owner_exe = 0100,
owner_all = 0700,
group_read = 040,
group_write = 020,
group_exe = 010,
group_all = 070,
others_read = 04,
others_write = 02,
others_exe = 01,
others_all = 07,
all_all = owner_all | group_all | others_all, // 0777
set_uid_on_exe = 04000,
set_gid_on_exe = 02000,
sticky_bit = 01000,
perms_mask = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit, // 07777
perms_not_known = 0xffff,
add_perms = 0x1000,
remove_perms = 0x2000,
symlink_perms = 0x4000
};
inline constexpr file_permissions
operator&(file_permissions x, file_permissions y)
{
return static_cast<file_permissions>
(static_cast<int>(x) & static_cast<int>(y));
}
inline constexpr file_permissions
operator|(file_permissions x, file_permissions y)
{
return static_cast<file_permissions>
(static_cast<int>(x) | static_cast<int>(y));
}
inline constexpr file_permissions
operator^(file_permissions x, file_permissions y)
{
return static_cast<file_permissions>
(static_cast<int>(x) ^ static_cast<int>(y));
}
inline constexpr file_permissions
operator~(file_permissions x)
{
return static_cast<file_permissions>(~static_cast<int>(x));
}
inline file_permissions &
operator&=(file_permissions & x, file_permissions y)
{
x = x & y;
return x;
}
inline file_permissions &
operator|=(file_permissions & x, file_permissions y)
{
x = x | y;
return x;
}
inline file_permissions &
operator^=(file_permissions & x, file_permissions y)
{
x = x ^ y;
return x;
}
我不完全确定您的接受标准是什么,但您可以让operator &
返回一个具有适当转换和explicit operator bool
:的包装类
#include <type_traits>
template<typename T> using Underlying = typename std::underlying_type<T>::type;
template<typename T> constexpr Underlying<T>
underlying(T t) { return Underlying<T>(t); }
template<typename T> struct TruthValue {
T t;
constexpr TruthValue(T t): t(t) { }
constexpr operator T() const { return t; }
constexpr explicit operator bool() const { return underlying(t); }
};
enum class Color { RED = 0xff0000, GREEN = 0x00ff00, BLUE = 0x0000ff };
constexpr TruthValue<Color>
operator&(Color l, Color r) { return Color(underlying(l) & underlying(r)); }
您的所有其他运营商都可以继续返回Color
,当然:
constexpr Color
operator|(Color l, Color r) { return Color(underlying(l) | underlying(r)); }
constexpr Color operator~(Color c) { return Color(~underlying(c)); }
int main() {
constexpr Color YELLOW = Color::RED | Color::GREEN;
constexpr Color WHITE = Color::RED | Color::GREEN | Color::BLUE;
static_assert(YELLOW == (WHITE & ~Color::BLUE), "color subtraction");
return (YELLOW & Color::BLUE) ? 1 : 0;
}
作用域枚举(使用enum class
或enum struct
创建的枚举)不是类。它们不能有成员函数,它们只提供封闭的枚举器(在命名空间级别不可见)。
列表中缺少运算符!=和==
枚举类型、整数类型和std::bitset
已经支持这些运算符,因此不需要重载它们。
并且为了允许排序,可能还希望重载<。
为什么要对位掩码进行排序?(a|b)大于(a|c)吗?std::ios::in
小于std::ios::app
吗?这有关系吗?关系运算符总是为枚举类型和整数类型定义的。
为了回答主要问题,您可以将&
实现为重载的非成员函数:
Foo operator&(Foo l, Foo r)
{
typedef std::underlying_type<Foo>::type ut;
return static_cast<Foo>(static_cast<ut>(l) & static_cast<ut>(r));
}
我相信,位掩码类型所需的所有操作都可以为作用域枚举定义,但不能定义等要求
Ci&Cj为非零,并且Ci&Cj为零
和:
值Y在对象X中设置是表达式X&Y为非零。
由于作用域枚举不支持impicit转换为整数类型,因此无法可靠地测试它是否为非零。你需要写if ((X&Y) != bitmask{})
,我认为这不是委员会的意图。
(我最初认为它们可以用来定义位掩码类型,然后记得我曾试图使用作用域枚举实现一个,但在测试零/非零时遇到了问题。)
编辑:我刚刚记得std::launch
是一个作用域枚举类型和位掩码类型。。。所以显然作用域的枚举可以是位掩码类型!
下面是枚举标志的简短示例。
#indlude "enum_flags.h"
ENUM_FLAGS(foo_t)
enum class foo_t
{
none = 0x00
,a = 0x01
,b = 0x02
};
ENUM_FLAGS(foo2_t)
enum class foo2_t
{
none = 0x00
,d = 0x01
,e = 0x02
};
int _tmain(int argc, _TCHAR* argv[])
{
if(flags(foo_t::a & foo_t::b)) {};
// if(flags(foo2_t::d & foo_t::b)) {}; // Type safety test - won't compile if uncomment
};
ENUM_FLAGS(T)是一个宏,在ENUM_FLAGS.h中定义(少于100行,可自由使用,没有任何限制)。
- 位移操作和位掩码未检测到重复字符
- OpenCV - 带有掩码的absdiff
- 生成前缀位掩码
- 如何从__m64值的 lsb 创建 8 位掩码?
- 如何对无符号长 int 进行位掩码?
- 删除K的背景掩码-意味着Python或C++中的集群/
- 如何在C++中优雅地处理位掩码
- 将uint64_t位掩码转换为 std::布尔数组
- 使输入二进制掩码适应 ITK 网格生成器
- 如何从 getifaddr 读取子网掩码
- 优化从子位掩码生成父位掩码
- 基于模式创建位掩码作为 constexpr
- 使用二进制掩码 C++ ITK 获取感兴趣区域
- C++中的运行时位复制(位掩码)
- 根据 IP 和掩码C++打印所有 IP
- C++设置"blank"或重置 ifstrean (ios) 的异常掩码
- OpenCV 检测带有掩码的斑点
- OPENCV:如何创建多边形形状的掩码
- 递归函数,用于使用位掩码 c++ 显示集合的所有子集
- 使用enum类的符合C++11标准的位掩码