I have run into a problem while writing C++ code that needs to compile in Visual Studio 2008 and in GCC 4.6 (and needs to also compile back to GCC 3.4): static const int class members.

Otherquestionshavecovered the rules required of static const int class members. In particular, the standard and GCC require that the variable have a definition in one and only one object file.

However, Visual Studio creates a LNK2005 error when compiling code (in Debug mode) that does include a definition in a .cpp file.

Some methods I am trying to decide between are:

Initialize it with a value in the .cpp file, not the header.

Use the preprocessor to remove the definition for MSVC.

Replace it with an enum.

Replace it with a macro.

The last two options are not appealing and I probably won't use either one. The first option is easy -- but I like having the value in the header.

What I am looking for in the answers is a good looking, best practice method to structure the code to make both GCC and MSVC happy at the same time. I am hoping for something wonderfully beautiful that I haven't thought of yet.

@Branko: Because it puts everything important about the class into one place. The header is like an outline of a class and the values are important for understanding how the class is used and what values are appropriate for array sizes, etc.
–
Zan LynxSep 1 '11 at 3:25

4 Answers
4

I generally prefer the enum way, because that guarantees that it will always be used as immediate value and not get any storage. It is recognized as constant expression by the compiler.

class Whatever {
enum { // ANONYMOUS!!!
value = 42;
};
...
}

If you can't go that way, #ifdef away the definition in the .cpp for MSVC, because if you ifdef away the value in declaration, it will always get storage; the compiler does not know the value, so it can't inline it (well, the "link time code generation" should be able to fix that up if enabled) and can't use it where constant is needed like value template arguments or array sizes.

If you don't dislike the idea of using non-standard hacks, for VC++ there's always __declspec(selectany). My understanding is that it will ensure that at link time, any conflicts are resolved by dropping all but one definition. You can potentially put this in an #ifdef _MSC_VER block.

Citing Zan "The first option is easy -- but I like having the value in the header."
–
osgxAug 31 '11 at 23:24

Yep. And if no better answer shows up in a couple days I will accept this one. It seems like the best option available, sadly.
–
Zan LynxSep 1 '11 at 3:28

@Lynx: IMO it's the worst option, because it forces the value to be stored in the binary image and does not allow inlining it.
–
Jan HudecSep 1 '11 at 6:52

1

@Jan: your first part is correct, but the second part is not, it still gets inlined under MSVC (this is due to the LTO). GCC's LTO should be able to do the same (and strip the unused variables that got placed in the data section via -fno-keep-static-consts)
–
NecrolisSep 1 '11 at 9:05

@Necrolis: Yes, LTO should be able to fix things up. But it's relying on optimizations, which may not happen from various subtle reasons, while providing the constant to compiler gives you other benefits here (it is constexpr then, so it can be used in places that need one).
–
Jan HudecSep 1 '11 at 9:37