11
struct A {
    static const int a = 5;

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

 };

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

The above code compiles. However if you go by Effective C++ book by Scott Myers(pg 14); We need a definition for a in addition to the declaration. Can anyone explain why this is an exception?

Zed
  • 57,028
  • 9
  • 76
  • 100
Pradyot
  • 2,897
  • 7
  • 41
  • 58

4 Answers4

22

C++ compilers allow static const integers (and integers only) to have their value specified at the location they are declared. This is because the variable is essentially not needed, and lives only in the code (it is typically compiled out).

Other variable types (such as static const char*) cannot typically be defined where they are declared, and require a separate definition.

For a tiny bit more explanation, realize that accessing a global variable typically requires making an address reference in the lower-level code. But your global variable is an integer whose size is this typically around the size of an address, and the compiler realizes it will never change, so why bother adding the pointer abstraction?

Walt W
  • 3,261
  • 3
  • 30
  • 37
19

By really pedantic rules, yes, your code needs a definition for that static integer. But by practical rules, and what all compilers implement because that's how the rules of C++03 are intended - no, you don't need a definition.

The rules for such static constant integers are intended to allow you to omit the definition if the integer is used only in such situations where a value is immediately read, and if the static member can be used in constant expressions.

In your return statement, the value of the member is immediately read, so you can omit the definition of the static constant integer member if that's the only use of it. The following situation needs a definition, however:

struct A {
    static const int a = 5;

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

 };

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

No value is read here - but instead the address of it is taken. Therefore, the intent of the C++03 Standard is that you have to provide a definition for the member like the following in some implementation file.

const int A::B::b;

Note that the actual rules appearing in the C++03 Standard says that a definition is not required only where the variable is used where a constant expression is required. That rule, however, if strictly applied, is too strict. It would only allow you to omit a definition for situation like array-dimensions - but would require a definition in cases like a return statement. The corresponding defect report is here.

The wording of C++0x has been updated to include that defect report resolution, and to allow your code as written.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Does it means that Walt W is wrong when he says : "C++ compilers allow static const integers (and integers only) to be defined at the location they are declared" ? I thought like him that the "static const int a = 5;" statement was both declaration and definition. If I understand correctly, it is only a declaration without any definition and the A::a can only be used in very specific cases. I'm intesrested in the final word ... – neuro Aug 21 '09 at 18:00
  • Yes, he is wrong too. That is only a declaration - it's not a definition. If you refer to it in cases that doesn't read a value immediately, a definition is needed. You seem to have it right in your comment. – Johannes Schaub - litb Aug 21 '09 at 18:55
  • Better? I suppose it wasn't the technical use of "definition" – Walt W Aug 21 '09 at 21:07
  • @Walt W, yeah i like it that way :) Have fun – Johannes Schaub - litb Aug 21 '09 at 21:15
  • This answer is more correct. See ISO C++ Defect Report 454 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2937.html#454), where this issue is described in more detail. Note that while the issue is fixed, the fix is not in C++03. – Pavel Minaev Aug 21 '09 at 21:16
  • However, it has CD1 Status. Somewhere i read that defect reports resolved with CD1 Status are normative, and are taken to be part of the current Standard (even though not appearing in C++03). But i'm still not exactly sure how to handle them. I think i should ask this as question on comp.std.c++ – Johannes Schaub - litb Aug 21 '09 at 21:20
  • At the very beginning of the page I linked to, there is the following text: – Pavel Minaev Aug 21 '09 at 21:23
  • "This document contains the C++ core language issues that have been categorized as Defect Reports by the Committee (J16 + WG21), that is, issues with status "DR," "WP," "CD1," and "TC1," along with their proposed resolutions. ONLY RESOLUTIONS FOR ISSUES WITH TC1 STATUS ARE PART OF THE INTERNATIONAL STANDARD FOR C++. The other issues are provided for informational purposes only, as an indication of the intent of the Committee. They should not be considered definitive until or unless they appear in an approved Technical Corrigendum or revised International Standard for C++." – Pavel Minaev Aug 21 '09 at 21:24
  • Does it mean, `static const int` is always a declaration no matter inside or outside the class? – Alcott Mar 28 '12 at 12:27
2

However, if you try the ternary operand without "defining" static consts, you get a linker error in GCC 4x:

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

So, although constructs like int k = A::CONSTVAL; are illegal in the current standard, they are supported. But the ternary operand is not. Some operators are more equal than others, if you get my drift :)

So much for "lax" rules. I suggest you write code conforming to the standard if you do not want surprises.

0

In general, most (and recent) C++ compilers allow static const ints

You just lucky, perhaps not. Try older compiler, such as gcc 2.0 and it will vehemently punish you with-less-than-pretty error message.

vehomzzz
  • 42,832
  • 72
  • 186
  • 216