【问题标题】:Is there a reason to use enum to define a single constant in C++ code?是否有理由使用枚举在 C++ 代码中定义单个常量?
【发布时间】:2010-11-25 13:10:52
【问题描述】:

定义一个整数常量以在函数中使用的典型方法是:

const int NumbeOfElements = 10;

在类中使用相同:

class Class {
...
    static const int NumberOfElements = 10;
};

然后它可以用作固定大小的数组绑定,这意味着它在编译时是已知的。

很久以前编译器不支持后一种语法,这就是使用枚举的原因:

enum NumberOfElementsEnum { NumberOfElements = 10; }

现在几乎所有广泛使用的编译器都支持函数内const int 和类内static const int 语法,是否有任何理由为此目的使用枚举?

【问题讨论】:

    标签: c++ enums constants


    【解决方案1】:

    原因主要是简洁。首先,enum 可以是匿名的:

     class foo {
        enum { bar = 1 };
     };
    

    这有效地将bar 作为一个整数常量引入。注意上面比static const int短。

    此外,如果enum 成员是&bar,则没有人可以写。如果你这样做:

     class foo {
        static const int bar = 1;
     }
    

    然后你班级的客户会这样做:

     printf("%p", &foo::bar);
    

    然后他会得到一个编译时链接器错误,foo::bar 没有定义(因为,​​好吧,作为一个左值,它不是)。在实践中,按照目前的标准,在不需要整数常量表达式的任何地方使用bar(即仅允许使用),它需要一个类外定义foo::bar. 需要这样一个表达式的地方是:enum 初始化器、case 标签、类型中的数组大小(new[] 除外)和整数类型的模板参数。因此,在其他任何地方使用bar 在技术上都需要定义。有关更多信息,请参阅 C++ Core Language Active Issue 712 - 目前还没有提议的解决方案。

    实际上,现在大多数编译器对此都比较宽容,并且可以让您摆脱static const int 变量的大多数“常识”用法,而无需定义。但是,极端情况可能会有所不同,因此许多人认为最好只使用匿名enum,因为这一切都一清二楚,而且完全没有歧义。

    【讨论】:

    • 嗯,即使使用 -pedantic -Wall -Wextra,gcc 也不会抱怨这一点。我猜是因为它在链接时间之前无法检测到错误,它只是放弃了尝试诊断这种不可移植的代码。
    • 好答案。您没有明确提及的另一件好事是枚举是右值,因此不会为它分配存储空间。如果您正在进行模板元编程和实例化大量类模板,最好肯定知道这一点,而不是依赖编译器优化。
    • 如果在课堂外没有定义static const int,也不会为此分配任何存储空间。此外,右值也可以为它们分配存储空间(例如,临时值是右值,它们肯定会使用存储空间)。
    • 请注意,目前 C++0x 草案中的措辞以及链接的缺陷报告使用的措辞确实允许在需要常量表达式的地方之外的许多用途。例如,如果您将缺陷报告中的示例更改为return x ? +S::a : +S::b;,那么代码就可以了——因为立即应用了左值到右值的转换。针对 C++03 的缺陷的主要解决方案位于 open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#454,并且已包含在当前工作文件中。从这个意义上说,一个提议的解决方案已经存在:)
    【解决方案2】:

    这两者是有区别的。据我所知,枚举没有地址。 static const ints 可以。因此,如果有人获取 const static int 的地址,丢弃 const,他可以修改该值(尽管编译器可能会忽略该更改,因为他认为它是 const)。这当然是纯粹的邪恶,你不应该这样做 - 但编译器无法阻止它。枚举不会发生这种情况。

    当然 - 如果您(出于某种原因)需要该 const 的地址,则需要静态 const int。

    简而言之 - enum 是一个右值,而 const static int 是一个左值。详情请见http://www.embedded.com/story/OEG20011129S0065

    【讨论】:

    • 如果没有定义,客户端将无法获取static const int 成员变量的地址。不过,右值/左值的区别很明显。
    • 客户端不会 - 但任何维护类并稍后添加代码的人。
    【解决方案3】:

    使用枚举有一个优势。枚举类型是一种类型,所以如果你定义,例如:

    enum EnumType { EnumValue1 = 10, EnumValue2 = 20 ... };
    

    你有这样的功能:

    void Function1(EnumType Value)
    

    编译器检查您是否将枚举 EnumType 的成员传递给函数,因此参数 Value 的有效值只有 EnumValue1 和 EnumValue2。如果您使用常量并将函数更改为

    void Function1(int Value)
    

    编译器会检查您是否将 int(任何 int、常量、变量或文字)传递给函数。

    枚举类型适用于对相关的常量值进行分组。只有一个 const 值,我看不到任何优势。

    【讨论】:

    • 是这样吗?我似乎记得您可以使用EnumValue1+1 作为EnumType,因为它是基础类型的成员,例如任何 int 都可以是 EnumType : int 的成员。我很想依靠这样的编译器检查,但我觉得我很失望。
    【解决方案4】:

    嗯,可移植性使用枚举的一个很好的理由。太好了,因为您不必担心您的编译器是否支持“static const int S = 10”...

    另外,据我所知,静态变量必须在某处定义,并声明,枚举值必须只声明。

    【讨论】:

    • 如果声明包含整数常量表达式初始化器,则不需要定义整数类型的 static const 值,但那里的规则非常模糊。看我的回答。
    【解决方案5】:

    使用“enum hack”的唯一原因是旧编译器不支持类内 const 定义,正如您在问题中所说的那样。因此,除非您怀疑您的代码将被移植到旧的编译器,否则您应该在 const 到期的地方使用 const。

    【讨论】:

      【解决方案6】:

      在你的情况下,我也会使用一个常量。但是,在其他情况下,我可能会添加其他相关的常量。像这样:

      const int TextFile = 1; // XXX Maybe add other constants for binary files etc.?
      

      在这种情况下,我会立即使用带有单个值的枚举,如下所示:

      enum FileType {
          TextFile = 1
          // XXX Maybe add other values for binary files etc.?
      }
      

      原因是当我在 switch 表达式中使用常量值时编译器会发出警告,如下所示:

      FileType type;
      // ...
      switch ( type ) {
          case TextFile:
             // ...
      }
      

      如果我决定添加另一个与现有值相关的常量值(在此示例中为不同类型的文件),几乎所有编译器都会发出警告,因为新值未在 switch 语句中处理。

      如果我改用 'int' 和常量,编译器就没有机会发出警告。

      【讨论】:

        【解决方案7】:

        直接在类定义中定义静态常量是后来添加到 C++ 的,许多人仍然坚持使用 enum 的旧解决方法。甚至可能还有一些旧的编译器仍在使用,它们不支持直接在类定义中定义的静态常量。

        【讨论】:

        • 一些编译器并不总是内联静态常量 int,而枚举总是内联 AFAIK。
        【解决方案8】:

        我认为没有理由使用枚举,实际上最好使用static const int,因为枚举有自己的类型(即使隐式转换为整数)。

        【讨论】:

        • 我不介意被否决,但很高兴让我知道原因。谢谢。
        • 为什么枚举有自己的类型是不好的?您的程序是否有不允许超过的类型配额?
        • 同意@Rob Kennedy。常量的强类型是枚举的point
        【解决方案9】:

        底线 - 使用 const。

        更多细节:

        我不是 C++ 专家,但这似乎是一个更普遍的设计问题。

        如果不是必须的,并且您认为枚举将增长到一个以上的值的可能性非常低/不存在,那么请使用常规 const。 即使您错了,并且在将来的某个时候会有更多的值,使 enum 成为正确的选择 - 一个简单的重构,您将 const 更改为 enum。

        【讨论】:

        • 从高级设计的角度来看,这与 enumconst 无关。这都是关于与每个构造相关的 C++ 怪癖。显而易见的答案在这里是错误的。
        猜你喜欢
        • 1970-01-01
        • 2016-01-18
        • 1970-01-01
        • 2023-03-16
        • 2020-09-18
        • 1970-01-01
        • 2015-08-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多