Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does declaring a "static const" member in a header file cause linker errors?

Tags:

c++

I have a class declaration(.h file) like so:

struct MyClass {
    static const uint32_t SIZE = sizeof(MyType);
};

When linking my program together, I get linker errors for MyClass::SIZE. nm confirms that the symbol is undefined. http://forums.devshed.com/c-programming-42/linker-errors-undefined-reference-to-static-member-data-193010.html seems to address my problem, indicating that "class static objects must also be declared outside any function or class just like normal globals."

I have two questions:

  1. Is this explanation valid for my case? If so, can you explain in a little more detail why this is true?
  2. What's the best way to fix it? I'd like to keep this member's initialization entirely in the .h file.
like image 835
Mike Avatar asked Mar 03 '11 16:03

Mike


2 Answers

Your problem may have nothing to do with someone taking the address of your variable. It could simply be the compiler opting not to use the variable as a constant expression even though it could. For example:

f(int const&);
struct X { enum { enum_val = 42 }; static int const static_mem = 42; };

f(5);
f(X::enum_val);
f(X::static_mem);

In the first two cases the compiler is required to use the input as a constant expression and the const& can be initialized with such. The last case however is different. Even though your intent is probably to use static_mem as a constant expression, and its completely legitimate to do so, the compiler is free to do otherwise and some will actually create a reference to the variable itself. This is "use" of the variable and thus you're required to have a definition of that variable somewhere in the program.

There's two ways to fix this issue:

1) Add a definition to your program.

2) Use enum instead: struct X { enum { static_mem = ? }; };

The first solution is necessary if you ever do intend that taking the address of your variable be possible. Chances are though that you did not or you would have created that definition already. The later solution forces the compiler to use X::static_mem as a constant expression since enum members don't actually exist as objects in the program. Based on your last statement in your question, I'm betting this is the solution you really want.

like image 137
Edward Strange Avatar answered Sep 29 '22 16:09

Edward Strange


The standard requires a definition for a static member integral constant only if its address is taken, otherwise the declaration with an initializer (what you have) is enough. That linker error message should mention which object/function takes an address of MyClass::SIZE.

like image 22
Maxim Egorushkin Avatar answered Sep 29 '22 18:09

Maxim Egorushkin