Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static constant class member declaration

Tags:

c++

gcc

linker

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?

like image 457
Zach Saw Avatar asked Sep 19 '12 06:09

Zach Saw


People also ask

What is a constant static member in C++?

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:

Can a static const member variable be initialized inside a class?

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.

Does a static data member need an out-of-class definition?

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:

Can a static data member appear in integral constant expressions?

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.


1 Answers

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.

like image 118
Bo Persson Avatar answered Sep 23 '22 01:09

Bo Persson