Dear Readers!

In this post I’m sharing an interesting observation I did recently about static members of classes when used with auto. Let us examine the follwing case, which a rookie or tired enough person late in the evening could easily write without hesitation:

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * ducks.h
 */

class QuackCounter {
public:
    // class machinery

    static auto getQuacks() {return numberOfQuacks;}

private:
    static auto numberOfQuacks;
}

This is a common error here. An unititialized variable, that fortunately produces a error: declaration of ‘auto numberOfQuacks’ has no initializer compile error (which is to be expected even without the static keyword in the game). This happens, because the compiler needs a value immediately to be able to deduce the appropriate type, so it is easy to see why this property of auto contributed greatly to its preference nowadays: you get a compile time error for unintialized variables. It is easily fixed by initializing the variable right then and there, like a tired/rookie person could easily do to give the compiler what it needs:

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * ducks.h
 */

class QuackCounter {
public:
    // class machinery
    
    static auto getQuacks() {return numberOfQuacks;}

private:
    static auto numberOfQuacks = 0;
}

Unfortunately though, this isn’t what the compiler needs at all and it will disagree yet again with something like this: error: ISO C++ forbids in-class initialization of non-const static member. Hmmm. What can we do? The solution is rather simple:

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * ducks.h
 */

class QuackCounter {
public:
    // class machinery
    
    static auto getQuacks() {return numberOfQuacks;}

private:
    static int numberOfQuacks;  // declare it here
}

.

C++

1
2
3
4
5
/*
 * ducks.cpp
 */
    
int QuackCounter::numberOfQuacks = 0;  // and define it in the .cpp file

The first change was the disposal of auto for the variable, but in the meantime, the method wasn’t touched, it still has auto. This situation is also good chance for understanding, that auto and static are not mutually exclusive, but rather any incompatibilites between the two arise from the very strict initialization rules imposed by auto itself.
The second change was the relocation of the variable definition to a .cpp file. But why should the definition be in the .cpp file? A quick search on stackoverflow.com gave me the right answers, of which the highlights are the following:

  • Static data members have external linkage and must be declared in exactly one translation unit, which makes them unfit for being defined inside a class (by Jesse Good)
  • In order for a static member variable (or any other global object) to get a unique address the linker must see exactly one definition of the static variable, in exactly one object file, and assign it an address (by Jonathan Wakely).

So there you go, lesson learned:

  1. auto and static are not mutually exclusive, they just need an appropriate partner to mate with
  2. static variables can only be defined in a .cpp file and only there, and as such they don’t allow auto