
Whilst compiling code using g++ I came across an error that a static constant member was not defined. The member in question was of integer type being defined in-line in the class, I took one look and could see the error even thought I had never personally come into contact with this before. How? Well I am a bit of a geek when it comes to the standard and often read it so that I can produce standard conforming (or better conforming) code.
Whilst writing this post I tried to create a minimal example which shows the error; yet I can not produce a simple example that fails so the code posted here is only to demonstration code. invalid_id is the point of interest
Header file:
namespace Bar
{
typedef unsigned int Id;
}
class Foo
{
public:
typedef Bar::Id Id;
static const Id invalid_id = Id(~0);
Foo(Id id);
Id m_id;
};
Foo* foo_create();
Source file:
Foo::Foo(Id id):m_id(id){}
Foo* foo_create()
{
return new Foo(Foo::invalid_id);
}
The problem is that according to the standard [1] an integral static constant class member can be declared and initialised in line yet it still requires a separate definition. Until this time neither g++ or MSCV has complained about not having it so I have never included it.
const Foo::Id Foo::invalid_id;
Upon inserting the above line in the source file so that g++ would compile and then testing with Visual Studio it produces warnings like the following:
warning LNK4006: “public: static unsigned int const X::Y” … already defined in Z.obj; second definition ignored
Where X,Y and Z have been substituted in for ease of reading.
A couple of these warnings are produced which is fine you can just ignore then as the compiler is doing the same. This is until you get to linking the library into an executable at which point it then spits out an error.
… error LNK2005: “public: static unsigned int const X::Y” … already defined in Z.obj
I have resorted to using the preprocessor to remove it from Visual Studio builds as I feel this is an MSCV error, if you know otherwise please inform me, and the solutions to the problem which MSDN provides do not seem valid for this code.
[1]
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. 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.