2

Possible Duplicate:
C++ - defining static const integer members in class definition

Note: There are several extant questions re similar issues, but I have reviewed many of them and cannot find an answer that explains this behavior:

Say I have code such as the following (in a header file)

class Foo {
    static const int TEST = 33;

    public:
    void willItWork(void) {
        printf("%d", std::max(TEST, 75));  // embedded platform, no streams
    }
};

int main(void) {
    Foo tester;
    tester.willItWork();
}

This will compile, but it will not link. I get the linker error

Error: L6218E: Undefined symbol Foo::TEST (referred from foo.o).

It only seems like passing the value to outside functions causes problems. Using TEST in ordinary expressions or functions within the class works fine. If I instead write willItWork() as

void willItWork(void) {
    int diff = TEST - 23;
    printf("%d", diff);
}

there is no error.

I found another question that referenced the C++ standard regarding this (Section 9.4.2):

If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a const-initializer which shall be an integral constant expression.

Since what I have done seems to be "within the rules," can anyone think of any possible explanation for this odd behavior?

I tried similar code on ideone and had no issue (however, I can not mimic the exact structure, i.e. with header files, there). Does this mean the linker I am using doesn't quite conform to the standard here?

Any insight is greatly appreciated. I can always provide more information, too.

Community
  • 1
  • 1
llakais
  • 1,577
  • 1
  • 12
  • 18
  • In this case passing the variable by value also will keep it from linking, as long as the function it is passed to is external (e.g. in a different class). – llakais Nov 15 '12 at 01:53

2 Answers2

4

If the compiler feels it needs the address of the static member variable, e.g., when binding the variable to a reference at some point, it will create a corresponding undefined symbol and you will have to define the member:

int const foo::TEST;

(in one translation unit). If the compiler only ever accesses a the value you can get away with not defining the object. Unless you need the type to be an int, you can use an enum instead and avoid the need for defining the member:

enum { TEST = 33 };

The term in the standard to look for is odr-used if I recall correctly.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
3

std::max takes its arguments by reference, not by value. Binding a reference to your static const requires an actual object, not just the value.

Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • I forget -- does the definition need the initializer, too? – Robᵩ Nov 15 '12 at 01:47
  • 1
    If the variable is already initialized at its declaration, it cannot be initialized at its definition. – Dietmar Kühl Nov 15 '12 at 01:50
  • If I pass the value to an external function of my own that takes arguments by value, it still generates the error. – llakais Nov 15 '12 at 01:50
  • @Robᵩ Okay, I think I figured it out...I was accessing my external function through a reference to the class that contained said function. Would that cause this problem in the same way? – llakais Nov 15 '12 at 02:02
  • And just out of curiosity, if `TEST` is essentially equivalent to a literal, does std::max() (and the rest of the library) then handle "actual" literals in some clever way that allows them to be passed by reference? – llakais Nov 15 '12 at 02:05