【问题标题】:using a static const int in a struct/class在结构/类中使用静态 const int
【发布时间】:2009-08-21 14:19:12
【问题描述】:
struct A {
    static const int a = 5;

    struct B {
       static const int b = a;
    };

 };

 int main() {
   return A::B::b;
 }

上面的代码编译。但是,如果您阅读 Scott Myers 的 Effective C++ 书(第 14 页); 除了声明之外,我们还需要一个定义。 谁能解释为什么这是一个例外?

【问题讨论】:

  • 代码确实包含“a”的定义。
  • 不,它不包含定义。
  • @Henk。并不真地。尝试将 'a' 或 'b' 的地址传递给函数,看看编译器会生成什么消息!

标签: c++


【解决方案1】:

C++ 编译器允许静态 const 整数(和仅限整数)在声明它们的位置指定其值。这是因为变量本质上是不需要的,并且只存在于代码中(它通常被编译出来)。

其他变量类型(如 static const char*)通常不能在声明它们的地方定义,需要单独定义。

为了进一步解释,请意识到访问全局变量通常需要在较低级别的代码中进行地址引用。但是你的全局变量是一个整数,它的大小通常是一个地址的大小,编译器意识到它永远不会改变,那么为什么还要添加指针抽象呢?

【讨论】:

  • +1,很好的答案。但是如果const 整数呢?我们可以在类中指定它们的值吗?
【解决方案2】:

按照真正迂腐的规则,是的,您的代码需要为该静态整数定义一个定义。 但是根据实际规则,以及所有编译器实现的内容,因为这就是 C++03 规则的意图——不,你不需要定义。

此类静态常量整数的规则旨在允许您省略定义,如果整数仅用于立即读取值的情况,并且静态成员可以在常量表达式中使用。

在您的 return 语句中,成员的值会立即被读取,因此如果这是唯一使用静态常量整数成员的定义,则可以省略它。但是,以下情况需要定义:

struct A {
    static const int a = 5;

    struct B {
       static const int b = a;
    };

 };

 int main() {
   int *p = &A::B::b;
 }

这里没有读取任何值——而是取而代之的是它的地址。因此,C++03 标准的意图是您必须在某些实现文件中为成员提供如下定义。

const int A::B::b;

请注意,出现在 C++03 标准中的 实际 规则表明,仅当使用常量表达式需要时才需要定义。但是,如果严格执行该规则,则过于严格。它只允许您省略诸如数组维度之类的情况的定义 - 但在返回语句之类的情况下需要定义。对应的缺陷报告为here

C++0x 的措辞已更新,以包含该缺陷报告解决方案,并允许您编写代码。

【讨论】:

  • 这是否意味着 Walt W 说错了:“C++ 编译器允许在声明它们的位置定义静态 const 整数(和仅整数)”?我和他一样认为“static const int a = 5;”声明既是声明又是定义。如果我理解正确,它只是一个没有任何定义的声明,并且 A::a 只能在非常特定的情况下使用。我对最后一句话很感兴趣......
  • 是的,他也错了。这只是一个声明——它不是一个定义。如果您在不立即读取值的情况下引用它,则需要定义。您的评论似乎是正确的。
  • 更好?我想这不是“定义”的技术用途
  • @Walt W,是的,我喜欢这样 :) 玩得开心
  • 这个答案更正确。请参阅 ISO C++ 缺陷报告 454 (open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2937.html#454),其中更详细地描述了此问题。请注意,虽然问题已得到修复,但 C++03 中并未提供该修复。
【解决方案3】:

但是,如果您在没有“定义”静态常量的情况下尝试使用三元操作数,则会在 GCC 4x 中出现链接器错误:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13795

因此,尽管int k = A::CONSTVAL; 之类的构造在当前标准中是非法的,但仍受支持。但三元操作数不是。有些运营商比其他运营商更平等,如果你明白我的意思:)

“宽松”的规则就这么多。如果你不想要惊喜,我建议你编写符合标准的代码。

【讨论】:

    【解决方案4】:

    一般来说,大多数(和最近的)C++ 编译器都允许静态常量整数

    你只是幸运,也许不是。尝试较旧的编译器,例如 gcc 2.0,它会以不漂亮的错误消息严厉惩罚您。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-07
      • 1970-01-01
      • 2011-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-08
      相关资源
      最近更新 更多