Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Whether redeclare a const static variable outside a class or not

In C++ Primer 4th 12.6.2, It recommend to redeclare a const static variable outside a class.

However, The code below passed in gcc 4.6.3.

#include <iostream>
using namespace std;

class X {
    public:
    const static int a = 1;
};

// const int X::a;

int main() {
    X x;
    cout << x.a << endl;
    return 0;
}

Should we redeclare it?

PS:

As recommended by Potatoswatter I added a function to use const static member as a reference:

const int X::a;

void test(const int& a) {
    cout << a << endl;
}

int main() {
    X x;
    test(X::a);
    return 0;
}

If we do not include const int X::a outside class X, it produced error as below

undefined reference to 'X::a'

It is a good practise to make a definition outside a class whether const static or not.

like image 724
Sam Avatar asked Mar 20 '23 17:03

Sam


2 Answers

No, you don't need to re-declare it as you have already declared and defined it in the single line:

const static int a = 1;

However, for static data members (including const static), if you only give its declaration in the class. You must define the static member outside of the class declaration, in namespace scope. For example:

class X
{
public:
      static int i; // declaration
};
int X::i = 0; // definition outside class declaration
like image 110
herohuyongtao Avatar answered Apr 26 '23 11:04

herohuyongtao


There's an exception to that rule for const static members that:

  1. Are of integer or enumeration type (pointers, references, floats need not apply)
  2. Never have their address taken or get bound to a reference

For static constexpr members, the type restriction is dropped (or, replaced with those of constexpr), and there must be an initializer at the in-class declaration.

In either case, the declaration is not considered to be a definition, despite having an initializer, so the object doesn't get an address until it's declared (hence defined) outside the class. For members of a template, that may be done in every translation unit (TU), for members of a non-template class it must be done in only one TU.

Although your example does compile, the practice isn't generally scalable because such variables can't be passed to generic pass-by-reference functions, including perfect forwarding. The book's advice is good.

Standard reference: [class.static.data] §9.4.2/3.

like image 31
Potatoswatter Avatar answered Apr 26 '23 12:04

Potatoswatter