为什么我不能将一个枚举作为另一个枚举的基础类型?
Why can't I have an enum as the underlying type of another enum?
为什么这个 C++ 无效?:
enum foo : unsigned { first_foo, second_foo };
enum bar : foo { best_foo = first_foo };
GCC 5.4.0 说:
/tmp/a.cpp:3:16: error: underlying type ‘foo’ of ‘bar’ must be an integral type
enum bar : foo { best_foo = first_foo };
我能理解如果 foo
是 float
或某个结构,或其他什么,为什么我会收到此错误。但这在语义、类型安全等方面对我来说似乎完全合法。我错过了什么?
嗯,不完全一样,但我想你可以使用 std::underlying_type
:
enum foo : unsigned { first_foo, second_foo };
enum bar : std::underlying_type_t<foo> { best_foo = first_foo };
C++11 [dcl.enum]/2:
The type-specifier-seq of an enum-base shall name an integral type; any cv-qualification is ignored.
枚举本身不是整数类型 – [basic.fundamental]/7:
Types bool
, char
, char16_t
, char32_t
, wchar_t
, and the signed and unsigned integer types are collectively called integral types.
附有非规范性脚注:
Therefore, enumerations are not integral; however, enumerations can be promoted to integral types as specified in [conv.prom].
要达到我想你想要的效果,其实还是很简单的:
enum bar : std::underlying_type<foo>::type { best_foo = first_foo };
对我来说,说一个枚举可以基于另一个枚举是一个逻辑错误。如果您认为 base 是存储枚举中定义的值的存储类型,我无法将其作为逻辑表达式来表示存储类型是枚举。因为枚举不仅仅是存储类型,它还包含一组有效值。
如果我们可以这样写:
enum A: int { ONE, TWO };
什么意思:
enum B: A{};
因为 A 不仅定义了底层类型(我称之为存储类型)而且还定义了一组有效值,B 应该只是枚举 A 的一个子集,这意味着您只能定义已经在 A 中定义的值?
现在可以说我们已经在 B 中定义了值 ONE,TWO 了吗?
现在是否可以添加更多值,例如:
enum B: A{THREE};
现在所有有效值都是一、二、三?
或者是我们只得到子集的意思:
enum B: A{ONE};
这意味着 B 只能使用已经在 A 中定义的值。简单地说,这让我很难将一个枚举作为另一个枚举的基础。
如果你打开那扇门,你也可以想到你想使用其他类型的底层存储类型,比如位域。
struct A { unsigned int a : 3; unsigned int B: 2; };
那么应该
enum B: A { ONE, TWO };
也有效?我相信不会! ;)
从逻辑上(我的观点)枚举的底层类型是它的存储类型。将一个枚举作为另一个枚举的底层存储类型是没有意义的。
当您向 C++ 添加内容时,您倾向于添加解决问题的最小数量。
enum A:int
语法可让您准确指定 enum A
如何存储为整数。这就是它所做的全部,它解决了问题。
enum A:B
其中 B
是一个枚举,可能有很多含义。 A
可以扩展 B
,或者 A
可以是具有不同名称的 B
基础类型的子集,或者 A
可以是一个严格限制为具有的枚举可以存储在 B
或 A
中的值的子集可以是一个枚举,其值被限制为 B
值的 "hull"。
其中,"same underlying type" 解决方案(使用 :int
语法)与 enum A:std::underlying_type_t<B>
一致。所以已经有办法做到这一点,而且不是特别麻烦。
除非有人对 enum A:B
的含义提出建议并充分说服委员会,否则不太可能获准。当存在多种不同的合理含义时,这使得选择任何一种含义变得更加困难。需要一个强有力的用例来解释为什么一种特定的含义是最好的,以及为什么将其纳入标准是值得的。
为什么这个 C++ 无效?:
enum foo : unsigned { first_foo, second_foo };
enum bar : foo { best_foo = first_foo };
GCC 5.4.0 说:
/tmp/a.cpp:3:16: error: underlying type ‘foo’ of ‘bar’ must be an integral type
enum bar : foo { best_foo = first_foo };
我能理解如果 foo
是 float
或某个结构,或其他什么,为什么我会收到此错误。但这在语义、类型安全等方面对我来说似乎完全合法。我错过了什么?
嗯,不完全一样,但我想你可以使用 std::underlying_type
:
enum foo : unsigned { first_foo, second_foo };
enum bar : std::underlying_type_t<foo> { best_foo = first_foo };
C++11 [dcl.enum]/2:
The type-specifier-seq of an enum-base shall name an integral type; any cv-qualification is ignored.
枚举本身不是整数类型 – [basic.fundamental]/7:
Types
bool
,char
,char16_t
,char32_t
,wchar_t
, and the signed and unsigned integer types are collectively called integral types.
附有非规范性脚注:
Therefore, enumerations are not integral; however, enumerations can be promoted to integral types as specified in [conv.prom].
要达到我想你想要的效果,其实还是很简单的:
enum bar : std::underlying_type<foo>::type { best_foo = first_foo };
对我来说,说一个枚举可以基于另一个枚举是一个逻辑错误。如果您认为 base 是存储枚举中定义的值的存储类型,我无法将其作为逻辑表达式来表示存储类型是枚举。因为枚举不仅仅是存储类型,它还包含一组有效值。
如果我们可以这样写:
enum A: int { ONE, TWO };
什么意思:
enum B: A{};
因为 A 不仅定义了底层类型(我称之为存储类型)而且还定义了一组有效值,B 应该只是枚举 A 的一个子集,这意味着您只能定义已经在 A 中定义的值?
现在可以说我们已经在 B 中定义了值 ONE,TWO 了吗? 现在是否可以添加更多值,例如:
enum B: A{THREE};
现在所有有效值都是一、二、三?
或者是我们只得到子集的意思:
enum B: A{ONE};
这意味着 B 只能使用已经在 A 中定义的值。简单地说,这让我很难将一个枚举作为另一个枚举的基础。
如果你打开那扇门,你也可以想到你想使用其他类型的底层存储类型,比如位域。
struct A { unsigned int a : 3; unsigned int B: 2; };
那么应该
enum B: A { ONE, TWO };
也有效?我相信不会! ;)
从逻辑上(我的观点)枚举的底层类型是它的存储类型。将一个枚举作为另一个枚举的底层存储类型是没有意义的。
当您向 C++ 添加内容时,您倾向于添加解决问题的最小数量。
enum A:int
语法可让您准确指定 enum A
如何存储为整数。这就是它所做的全部,它解决了问题。
enum A:B
其中 B
是一个枚举,可能有很多含义。 A
可以扩展 B
,或者 A
可以是具有不同名称的 B
基础类型的子集,或者 A
可以是一个严格限制为具有的枚举可以存储在 B
或 A
中的值的子集可以是一个枚举,其值被限制为 B
值的 "hull"。
其中,"same underlying type" 解决方案(使用 :int
语法)与 enum A:std::underlying_type_t<B>
一致。所以已经有办法做到这一点,而且不是特别麻烦。
除非有人对 enum A:B
的含义提出建议并充分说服委员会,否则不太可能获准。当存在多种不同的合理含义时,这使得选择任何一种含义变得更加困难。需要一个强有力的用例来解释为什么一种特定的含义是最好的,以及为什么将其纳入标准是值得的。