使用固定值枚举器

时间:2015-10-03 15:37:45

标签: c++ c++11 enums

假设以下简单示例:

enum class Test { One = 1, Two = 2, Three = 3 };

int main()
{
    Test t{};
}

上面的代码似乎可以在Clang,GCC和MSVC上正常编译。我担心的是,用于表示各个枚举数的数值范围的底层整数类型完全能够将0表示为值,而0值不会映射到常量本身。正是这种差异令人困惑(整数类型范围与枚举枚举器的范围相比)。从t的角度来看,int的值似乎是“明确定义的”,但在某种意义上它没有很好地定义,作为标量,它不会映射到其中一个枚举常量

我的搜索结果为this SO post,但最佳答案是非常技术,我不太明白。我从一个稍微不同的角度提出这个问题,看看我是否能得到一个对我更有意义的答案。

具有固定值枚举器的枚举与没有固定值枚举器的枚举之间是否存在不同的规则和/或保证?对于具有未明确分配的枚举数的枚举,上面的代码非常有意义,这是一个令人困惑的固定值案例。

3 个答案:

答案 0 :(得分:1)

枚举中的枚举数用于三个不同的目的:

  1. 他们为此枚举类型的值定义名称。
  2. 如果底层类型未修复,它们会为枚举类型的对象塑造有效值范围
  3. 如果它没有修复,它们会影响枚举的基础类型
  4. 有效值的范围可以包括没有枚举数的值。这当然可能令人困惑,例如当你编写一个switch语句时,它应该涵盖枚举的所有值。

    我只是猜测,但是枚举器和有效枚举值之间没有1对1映射的原因可能是与C的兼容性。在C中,枚举器具有类型int,因此表示枚举数必须是调查员所代表的int。因此,您无法将枚举数A = 1映射到值0enum可能已从整数#define进化而来。

    现在,如果您从int转换为枚举类型,则不需要复杂的程序逻辑(la switch)将枚举器值(int s)映射到存储在枚举类型的对象中的值。实际上,C要求枚举类型与某些整数类型兼容。这意味着枚举类型的的表示必须与兼容整数类型的表示相同。举个例子:

    enum my_enum
    {
        ENUMERATOR = 42
    };
    
    enum my_enum x = ENUMERATOR;
    

    如果my_enumint兼容,则x中存储的值的表示必须与42的表示形式相同。

    兼容性要求将类型紧密地绑定在一起,据我所知,它们可以互换使用:

    enum my_enum
    {
        ENUMERATOR_A = 0,
        ENUMERATOR_B = ~0
    };
    
    void foo(int);
    
    int main() {
        foo(0);
    }
    
    void foo(enum my_enum x) {}
    

    clang和gcc不会将此视为错误,后者使用int作为my_enum的兼容类型。

    因为枚举类型本质上是整数类型的typedef,所以可以存在没有枚举数的值。

    C ++包含关于枚举和整数类型之间关系的一些提示,例如[expr.static.cast]和[conv.integral]谈论在积分和枚举类型之间转换时不改变值。但是,我不确定这是否有意义,因为除了通过往返转换之外,我不确定如何观察这种变化。

    在枚举类型及其基础类型之间,C ++的严格别名规则中没有例外。

    请注意,在C中,我们可以利用这种关系方便地使用位标志:

    enum FLAGS
    {
        FLAG_A = 1,
        FLAG_B = 2
    };
    
    void foo(enum FLAGS x);
    
    int main() { foo(FLAG_A | FLAG_B); }
    

    在C ++中,这是一个类型错误:FLAG_A | FLAG_Bint,不能隐式转换为FLAGS。虽然可以编写显式转换,例如foo( static_cast<FLAGS>(FLAG_A | FLAG_B) ),但是有更方便的方法可以在C ++中编写位集。

    问题的零初始化部分可能也非常相关:如果可以通过单个memset或静态数据实现它,它非常有用,放置它在.bss部分。因此,在类型中使用值为0的值非常有用。

    必须补充一点,指针到数据成员通常有一个空指针值由所有位0表示,所以它不是闻所未闻打破这个有用的财产。

答案 1 :(得分:0)

总结一下,保证只引用枚举指定的可能值范围(minValue,maxValue)。

没有固定值的枚举具有标准(第7.2 / 2节)

保证的枚举值

枚举保证在其最小定义值和最大定义值之间的范围内保存任何值,并且未指定它如何处理该范围之外的数字。所有操作都是在其基础类型

上进行的

同样根据§5.2.9/ 10,我们有关于如何将积分转换为枚举的规则:

  

可以将整数或枚举类型的值显式转换为枚举类型。如果是,则值不变   原始值在枚举值(7.2)的范围内。   否则,结果值未指定(可能不在   那个范围)。

因此,将整数转换为范围之外的枚举值会给出未指定的值。这是一般规则,无论是否在声明中指定了枚举器值。但是,范围是由底层类型给出的,它总是可以代表xero,所以它不是未定义的(参见relevant answer)。

请参阅Link to relevant question

答案 2 :(得分:0)

  

具有固定值枚举器的枚举与没有固定值枚举器的枚举之间是否存在不同的规则和/或保证?

无。您应该考虑枚举只是类型安全(仅在c ++ 11枚举类中保证类型安全)整数。