in Foo.h:
class Foo
{
public:
Foo();
static const unsigned int FOOBAR = 10;
static const unsigned int BARFOO = 20;
private:
unsigned int m_FooBar;
bool m_Bar;
void Bar();
};
in Foo.cpp:
Foo::Foo()
: m_FooBar(FOOBAR), // this works
m_Bar(false)
{
}
void Foo::Bar()
{
//m_FooBar = m_Bar ? FOOBAR : BARFOO; // linker fails *1
m_FooBar = FOOBAR; // ok
}
I'm compiling with GCC 4.5.3. Is there any reason why the linker would fail when line *1 is uncommented?
Foo.o: In function 'Foo::Bar' (name unmangled):
Foo.cpp: undefined reference to `Foo::FOOBAR'
Foo.cpp: undefined reference to `Foo::BARFOO'
Tried with VC2005, 2008, 2010 and CB2010. They all compiled and linked fine. Why does GCC fail in this case?
Given the answer here, why doesn't the other popular compilers fail like GCC? One way or another, it has to be a bug, either for GCC or the other popular compilers. Or is there a more reasonable explanation?
Constant static members. If a static data member of integral or enumeration type is declared const (and not volatile), it can be initialized with an initializer in which every expression is a constant expression, right inside the class definition:
C++ standard says only "static const int" and "static const enum" can be initialized inside class definition. For more, refer [C++11: 9.4.2/3] and [C++03: 9.4.2/2]. If a static const member variable is initialized to a static const member variable of another class before the constructor is called, initialization is not guaranteed to work.
It does not need an out-of-class definition: If a static data member of integral or enumeration type is declared const (and not volatile ), it can be initialized with an initializer in which every expression is a constant expression, right inside the class definition:
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.
Formally, the header only declares the static constants, and they also have to be defined (at least in C++03). However, if you only use their values, you most often get away with this.
In C++11 this is more formally specified as requiring a definition when the static is "odr-used". The *1
line is an example of this. The triadic operator tries to form a reference to the values, and the compiler (or linker actually) realizes that it cannot.
The C++11 standard says
9.4.2 Static data members
§3...
The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With