C++11和[17.5.2.1.3]位掩码类型
C++11 and [17.5.2.1.3] Bitmask Types
标准允许在整数类型、enum
和std::bitset
之间进行选择。
既然有这些选择,为什么库实现者会使用一个而不是另一个
举个例子,llvm的libcxx似乎使用了(至少)其中两个实现选项的组合:
ctype_base::mask
使用整数类型来实现:<__locale>
regex_constants::syntax_option_type
使用enum
+重载运算符来实现:<regex>
gcc项目的libstdc++使用所有三个:
ios_base::fmtflags
使用枚举+重载运算符实现:<bits/ios_base.h>
CCD_ 10使用整数类型来实现,regex_constants::match_flag_type
使用std::bitset
实现两者:<bits/regex_constants.h>
AFAIK,gdb无法"检测"这三个选项中任何一个的位字段,因此wrt增强调试不会有任何区别。
enum
解决方案和整数类型解决方案应始终使用相同的空间。std::bitset
似乎不能保证sizeof(std::bitset<32>) == std::uint32_t
,所以我看不出std::bitset
有什么特别吸引人的地方。
enum
解决方案的类型安全性似乎稍差,因为掩码的组合不会生成枚举器。
严格来说,前面提到的是关于n3376,而不是FDIS(因为我无法访问FDIS)。
如能在这方面获得任何启示,我们将不胜感激。
真正令人惊讶的是,该标准仅将其限制为三种替代方案。为什么类类型不能被接受?无论如何…
- 积分类型是最简单的选择,但它们缺乏类型安全性。非常旧的遗留代码将倾向于使用这些,因为它们也是最古老的
- 枚举类型是安全但繁琐的,在C++11之前,它们往往固定在
int
的大小和范围内 std::bitset
可能具有更多的类型安全性,因为bitset<5>
和bitset<6>
是不同的类型,并且不允许加法,但在其他方面是不安全的,就像积分类型一样。如果他们允许从std::bitset<N>
派生类型,这就不会成为问题
显然,enum
是理想的替代方案,但经验证明,类型安全确实是不必要的。因此,他们向实现者抛出了一根骨头,并允许他们采取更容易的路线。简而言之,懒惰导致实现者选择int
或bitset
有点奇怪的是,不允许从bitset
派生的类型,但实际上这只是一件小事。
子句提供的主要规范是在这些类型上定义的一组操作(即逐位运算符)。
我更喜欢使用枚举,但有时使用整数是有正当理由的。通常,ctype_base::mask
与本机OS头进行交互,从ctype_base::mask
到<ctype.h>
的映射定义了isupper
和islower
等使用的常量,如_CTYPE_L
和_CTYPE_U
。使用整数可能会使直接与本机OSAPI一起使用ctype_base::mask更容易。
我不知道为什么libstdc++的<regex>
使用std::bitset
。提交该代码后,我在脑海中记下了在某个时刻用枚举替换整数类型,但<regex>
不是我优先处理的问题。
为什么标准允许以不同的方式实现库?答案是:为什么不呢?
正如您所看到的,这三个选项显然都用于某些实现中。如果可以避免的话,标准不希望使现有的实现不一致。
使用位集的一个原因可能是它的大小比枚举或整数更适合。并非所有系统都有std::uint32_t
。也许bitset<24>
在那里会更好用?
- 位移操作和位掩码未检测到重复字符
- 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) 的异常掩码
- 将位掩码类型与零进行比较的正确方法
- 如何在积分类型的模板函数中选择snprinf掩码
- C++11和[17.5.2.1.3]位掩码类型
- C++格式掩码没有命名类型