Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defining static const integer members in class definition

My understanding is that C++ allows static const members to be defined inside a class so long as it's an integer type.

Why, then, does the following code give me a linker error?

#include <algorithm> #include <iostream>  class test { public:     static const int N = 10; };  int main() {     std::cout << test::N << "\n";     std::min(9, test::N); } 

The error I get is:

test.cpp:(.text+0x130): undefined reference to `test::N' collect2: ld returned 1 exit status 

Interestingly, if I comment out the call to std::min, the code compiles and links just fine (even though test::N is also referenced on the previous line).

Any idea as to what's going on?

My compiler is gcc 4.4 on Linux.

like image 289
HighCommander4 Avatar asked Jun 11 '10 20:06

HighCommander4


People also ask

What is static const int in C?

“static const” is basically a combination of static(a storage specifier) and const(a type qualifier). The static determines the lifetime and visibility/accessibility of the variable.

Can static members be const?

A static data member can be of any type except for void or void qualified with const or volatile. You cannot declare a static data member as mutable.

How do you initialize static constant characteristics of a class?

For std::string , it must be defined outside the class definition and initialized there. static members must be defined in one translation unit to fulfil the one definition rule. If C++ allows the definition below; struct C { static const string b = "hi"; };

How do you declare a static member in C++?

We can define class members static using static keyword. When we declare a member of a class as static it means no matter how many objects of the class are created, there is only one copy of the static member. A static member is shared by all objects of the class.


2 Answers

My understanding is that C++ allows static const members to be defined inside a class so long as it's an integer type.

You are sort of correct. You are allowed to initialize static const integrals in the class declaration but that is not a definition.

Interestingly, if I comment out the call to std::min, the code compiles and links just fine (even though test::N is also referenced on the previous line).

Any idea as to what's going on?

std::min takes its parameters by const reference. If it took them by value you'd not have this problem but since you need a reference you also need a definition.

Here's chapter/verse:

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.

See Chu's answer for a possible workaround.

like image 171
Edward Strange Avatar answered Sep 17 '22 22:09

Edward Strange


Bjarne Stroustrup's example in his C++ FAQ suggests you are correct, and only need a definition if you take the address.

class AE {     // ... public:     static const int c6 = 7;     static const int c7 = 31; };  const int AE::c7;   // definition  int f() {     const int* p1 = &AE::c6;    // error: c6 not an lvalue     const int* p2 = &AE::c7;    // ok     // ... } 

He says "You can take the address of a static member if (and only if) it has an out-of-class definition". Which suggests it would work otherwise. Maybe your min function invokes addresses somehow behind the scenes.

like image 32
HostileFork says dont trust SE Avatar answered Sep 17 '22 22:09

HostileFork says dont trust SE