枚举与静态常量

enum vs static consts

本文关键字:常量 静态 枚举      更新时间:2023-10-16

我目前正在考虑一个问题,即命名空间枚举还是静态常量命名空间组更可取。默认选择应该是什么,为什么?

选项 1:

namespace Direction
{
    enum Direction
    {
        north,
        east,
        south,
        west,
    };
}

选项 2:

namespace Direction
{
    static const unsigned char north = 0;
    static const unsigned char east = 1;
    static const unsigned char south = 2;
    static const unsigned char west = 3;
}

两者都有其优点和缺点。

专业枚举:

  1. 某些类型安全:

    void foo(Direction dir); // the compiler won't allow you to just pass an int or a value of an unrelated enum without explicitly casting it
    

魂斗罗枚举:

  1. 类型安全性相当有限:

    enum A
    {
        Entry1 = 1
    };
    enum B
    {
        Entry2 = 10
    };
    A a;
    if(a == Entry2)
        ; // ouch!
    
  2. 不支持除 int 以外的任何其他类型 - 在 C++ 11 之前,不能只有一个枚举,例如长长、短或字符

  3. 枚举的命名空间是次优的

    1. 如果不将枚举包装到单独的命名空间中,则其所有成员都将污染周围的命名空间。

    2. 如果确实将枚举包装到单独的命名空间中,则在使用枚举本身作为类型时会获得一些冗余:然后必须以 Direction::D irection 的方式声明一个方向变量(当不执行"使用 Direction::D irection 时"时,这会让它们再次污染外部命名空间(最后在代码的那部分,其中 using 指令生效)),以便能够以 Direction::north 而不是 north 的方式为其成员命名

专业静态常量:

  1. 在 C++ 11 之前的 C++ 中提供更好的类型支持 - 例如,可以使用无符号字符等类型作为常量
  2. 适当的范围 - 不会污染外部命名空间,而无需通过 using 指令明确要求它(即使这样也只能在有限的范围内)

逆静态常量:

  1. 甚至比枚举更不安全 - 不再能够像这样声明函数原型:

    void foo(Direction dir);
    

    但必须通过以下方式执行此操作:

    void foo(unsigned char dir); // now each variable of type unsigned char or of a type that can implicitly be casted into unsigned char can be passed, even if its totally unrelated to the expected "enumeration" or if the value does not match the value of any of the expected consts
    

编辑:在这里,我找到了一篇关于枚举类型安全限制的有趣文章:http://www.drdobbs.com/enumerations/184401797

最大的区别是打字。 枚举具有不同的类型;静态常量必须具有现有的积分类型(尽管它可以在其他地方使用)。 哪一个更可取取决于你想要什么:在Direction的情况下,你可能想要唯一类型,枚举更可取。 在其他情况下,什么你真正想要的是一个具有整数类型的命名常量,比如作为数组的维度。 在这些情况下,静态常量是可能更可取。

C++11 通过强类型枚举和改进的作用域来解决所有反枚举点。

对于一组固定的值,例如您的基本方向示例,我会使用 enum。

使用枚举,您可以将属于概念的所有常量绑定在一起(使用名为 enum 的唯一 c++ 标识符)。

赫伯·萨特写到更喜欢新风格的演员(static_cast)而不是C演员。他的一个论点(以及其他论点)是,它们可以通过源代码中的正则表达式找到。

回到你的问题,这意味着如果你采取enum你可以通过代码库来查找要一起使用的常量。对于命名空间中的常量,这是不可能的。