By HighCommander4


2010-06-11 20:26:48 8 Comments

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.

7 comments

@Carlo Wood 2017-09-11 23:38:15

As of C++11 you can use:

static constexpr int N = 10;

This theoretically still requires you to define the constant in a .cpp file, but as long as you don't take the address of N it is very unlikely that any compiler implementation will produce an error ;).

@HostileFork 2010-06-11 20:48:49

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.

@Rakete1111 2017-09-18 19:22:54

std::min takes its parameters by reference, which is why a definition is required.

@karadoc 2011-05-28 07:04:03

Here's another way to work around the problem:

std::min(9, int(test::N));

(I think Crazy Eddie's answer correctly describes why the problem exists.)

@Orient 2013-04-19 05:31:03

or even std::min(9, +test::N);

@Opux 2017-04-26 21:53:09

Here's the big question though: is all this optimal? I don't know about you guys, but my big attraction to skipping the definition is that it should take up no memory and no overhead in using the const static.

@fredoverflow 2010-06-11 21:02:34

C++ allows static const members to be defined inside a class

Nope, 3.1 ยง2 says:

A declaration is a definition unless it declares a function without specifying the function's body (8.4), it contains the extern specifier (7.1.1) or a linkage-specification (7.5) and neither an initializer nor a functionbody, it declares a static data member in a class definition (9.4), it is a class name declaration (9.1), it is an opaque-enum-declaration (7.2), or it is a typedef declaration (7.1.3), a using-declaration (7.3.3), or a using-directive (7.3.4).

@Crazy Eddie 2010-06-11 20:36:30

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.

http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr038.htm

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.

@HighCommander4 2010-06-11 20:41:50

I see, that's interesting. In that case, what is the difference between providing the value at the point of declaration versus providing the value at the point of definition? Which one is recommended?

@Crazy Eddie 2010-06-11 20:46:58

Well, I believe that you can get away without a definition so long as you never actually "use" the variable. If you only use it as a part of a constant expression then the variable is never used. Otherwise there doesn't seem to be a huge difference besides being able to see the value in the header - which may or may not be what you want.

@Dale Wilson 2012-08-17 16:54:37

The terse answer is static const x=1; is an rvalue but not an lvalue. The value is available as a constant at compile time (you can dimension an array with it) static const y; [no initializer] must be defined in a cpp file and may be used either as an rvalue or an lvalue.

@Aaron McDaid 2015-07-14 11:38:04

It would be nice if they could extend/improve this. initialized-but-not-defined objects should, in my opinion, be treated the same as literals. For example, we are allowed to bind a literal 5 to a const int&. So why not treat the OP's test::N as the corresponding literal?

@Stephen Chu 2010-06-11 20:39:46

Another way to do this, for integer types anyway, is to define constants as enums in the class:

class test
{
public:
    enum { N = 10 };
};

@Crazy Eddie 2010-06-11 20:49:38

And this would probably solve the problem. When N is used as a parameter for min() it will cause a temporary to be created rather than try to refer to a supposedly existing variable.

@Agostino 2018-04-10 09:06:11

This had the advantage that it can be made private.

@Amardeep AC9MF 2010-06-11 20:30:30

Not just int's. But you can't define the value in the class declaration. If you have:

class classname
{
    public:
       static int const N;
}

in the .h file then you must have:

int const classname::N = 10;

in the .cpp file.

@HighCommander4 2010-06-11 20:32:37

I am aware that you can declare a variable of any type inside the class declaration. I said that I thought static integer constants could also be defined inside the class declaration. Is this not the case? If not, why is it that the compiler does not give an error at the line where I try to define it inside the class? Moreover, why does the std::cout line not cause a linker error, but the std::min line does?

@Amardeep AC9MF 2010-06-11 20:35:52

No, can't define static members in the class declaration because the initialization emits code. Unlike an inline function which also emits code, a static definition is globally unique.

@AnT 2010-06-11 20:39:19

@HighCommander4: You can supply an initializer for the static const integral member in the class definition. But that still does not define that member. See Noah Roberts answer for details.

Related Questions

Sponsored Content

18 Answered Questions

[SOLVED] Are static class variables possible?

8 Answered Questions

[SOLVED] Meaning of 'const' last in a function declaration of a class?

35 Answered Questions

[SOLVED] Difference between static class and singleton pattern?

11 Answered Questions

[SOLVED] Static constant string (class member)

5 Answered Questions

[SOLVED] Defining static members in C++

  • 2010-08-21 04:49:39
  • Jaguar
  • 31743 View
  • 25 Score
  • 5 Answer
  • Tags:   c++ static

0 Answered Questions

C++ linker error when access to static member in nested class

  • 2014-12-21 07:54:41
  • slonma
  • 21 View
  • 0 Score
  • 0 Answer
  • Tags:   c++ static nested

1 Answered Questions

[SOLVED] static const member of a struct is not defined

  • 2014-12-18 20:53:22
  • John
  • 92 View
  • 3 Score
  • 1 Answer
  • Tags:   c++

3 Answered Questions

4 Answered Questions

[SOLVED] How to define static const member?

4 Answered Questions

[SOLVED] static members and consts

  • 2010-09-13 20:18:21
  • mati
  • 290 View
  • 2 Score
  • 4 Answer
  • Tags:   c++ static const

Sponsored Content