46

如果您想将某个常量值与一个类相关联,这里有两种方法可以实现相同的目标:

class Foo
{
public:
    static const size_t Life = 42;
};

class Bar
{
public:
    enum {Life = 42};
};

从客户的角度来看,它们在句法和语义上似乎是相同的:

size_t fooLife = Foo::Life;
size_t barLife = Bar::Life;

除了纯粹的风格问题之外,还有什么理由会比另一种更受欢迎吗?

4

6 回答 6

63

hack 曾经是必要的enum,因为许多编译器不支持值的就地初始化。由于这不再是问题,请选择其他选项。现代编译器还能够优化此常量,使其不需要存储空间。

不使用变体的唯一原因static const是如果您想禁止获取值的地址:您不能获取enum值的地址而可以获取常量的地址(这会提示编译器保留空间毕竟是值,但前提它的地址确实被占用了)。

此外,除非也明确定义了常量,否则获取地址将产生链接时错误。请注意,它仍然可以在声明的位置进行初始化:

struct foo {
    static int const bar = 42; // Declaration, initialization.
};

int const foo::bar; // Definition.
于 2008-10-15T14:46:35.353 回答
11

它们不相同:

size_t *pLife1 = &Foo::Life;
size_t *pLife2 = &Bar::Life;
于 2008-10-15T14:46:19.957 回答
9

一个区别是枚举定义了一种可以用作方法参数的类型,例如,以获得更好的类型检查。两者都被编译器视为编译时常量,因此它们应该生成相同的代码。

于 2008-10-15T14:50:18.527 回答
7

static const值被视为 r 值,就像enum您将看到的 99% 的代码一样。常量 r 值永远不会为它们生成内存。优势enum常数是它们不能成为另外 1% 的 l 值。这些static const值是类型安全的,并允许浮点数、c 字符串等。

Foo::Life如果编译器具有与之关联的内存,则编译器将生成一个左值。通常的方法是获取它的地址。例如&Foo::Life;

这是 GCC 将使用该地址的一个微妙示例:

int foo = rand()? Foo::Life: Foo::Everthing;

编译器生成的代码使用 和 的Life地址Everything。更糟糕的是,这只会产生关于 和 的缺失地址的链接器Foo::Life错误Foo::Everything。这种行为完全符合标准,尽管显然是不可取的。还有其他编译器特定的方式可以发生这种情况,并且所有标准都符合。

一旦你有一个符合要求的 c++11 编译器,正确的代码将是

class Foo {
 public:
  constexpr size_t Life = 42;
};

这保证始终是一个左值,并且它是类型安全的,两全其美。

于 2008-10-17T05:47:29.417 回答
5

好吧,如果需要,您可以获取静态 const 成员值的地址。您必须声明一个单独的枚举类型的成员变量来获取它的地址。

于 2008-10-15T14:47:32.807 回答
5

另一个第三种解决方案?

一个细微的区别是枚举必须在标题中定义,并且对所有人可见。当您避免依赖时,这很痛苦。例如,在 PImpl 中,添加枚举会适得其反:

// MyPImpl.hpp

class MyImpl ;

class MyPimpl
{
   public :
      enum { Life = 42 } ;
   private :
      MyImpl * myImpl ;
}

另一个第三种解决方案是问题中提出的“const static”替代方案的变体:在标头中声明变量,但在源代码中定义它:

// MyPImpl.hpp

class MyImpl ;

class MyPimpl
{
   public :
      static const int Life ;
   private :
      MyImpl * myImpl ;
}

.

// MyPImpl.cpp
const int MyPImpl::Life = 42 ;

请注意,MyPImpl::Life 的值对 MyPImpl 的用户(包括 MyPImpl.hpp)是隐藏的。

这将使 MyPimpl 作者能够根据需要更改“Life”的值,而无需 MyPImpl 用户重新编译,这是 PImpl 的总体目标。

于 2008-10-15T22:30:01.173 回答