C++11和[17.5.2.1.3]位掩码类型

C++11 and [17.5.2.1.3] Bitmask Types

本文关键字:掩码 类型 C++11      更新时间:2023-10-16

标准允许在整数类型、enumstd::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是理想的替代方案,但经验证明,类型安全确实是不必要的。因此,他们向实现者抛出了一根骨头,并允许他们采取更容易的路线。简而言之,懒惰导致实现者选择intbitset

有点奇怪的是,不允许从bitset派生的类型,但实际上这只是一件小事。

子句提供的主要规范是在这些类型上定义的一组操作(即逐位运算符)。

我更喜欢使用枚举,但有时使用整数是有正当理由的。通常,ctype_base::mask与本机OS头进行交互,从ctype_base::mask<ctype.h>的映射定义了isupperislower等使用的常量,如_CTYPE_L_CTYPE_U。使用整数可能会使直接与本机OSAPI一起使用ctype_base::mask更容易。

我不知道为什么libstdc++的<regex>使用std::bitset。提交该代码后,我在脑海中记下了在某个时刻用枚举替换整数类型,但<regex>不是我优先处理的问题。

为什么标准允许以不同的方式实现库?答案是:为什么不呢?

正如您所看到的,这三个选项显然都用于某些实现中。如果可以避免的话,标准不希望使现有的实现不一致。

使用位集的一个原因可能是它的大小比枚举或整数更适合。并非所有系统都有std::uint32_t。也许bitset<24>在那里会更好用?