开发者

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

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.


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.


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.


Quoting myself from No definition available for static const member with initializer?

And from 9.4.2/4:

If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions within its scope. The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.

From these references we can infer ("...shall still be defined..." in 9.4.2/4) that if it's not defined then the program isn't well-formed.

@David Rodríguez - dribeas points out that you must be taking the address of the static member in your program somewhere. If you can avoid taking the address then there's no need for the definition in the implementation file (alternately you aren't taking the address and have a buggy compiler). Otherwise you must have the definition.


If you've to do this:

//.h file
struct MyClass 
{
    static const uint32_t SIZE = sizeof(MyType); //this is declaration!

}; 

//.cpp file
const uint32_t MyClass::SIZE; //this is definition - necessary!


  1. Most likely, but without any error messages, it's hard to say.

  2. Use a static const int. You can initialize it in the header, and you don't need to declare it in the cpp.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜