Template getID calling regular getID

Viewed 113

I have seen that code somewhere and I don't know how it works. pls explain :( My guess is that the template function is saving the state of other function.

Code:

#include <iostream>

int getID() {
    static int id = 0;
    return id++;
}

template <typename T>
int getID2() {
    static int id2 = getID();
    return id2;
}

int main() {
    std::cout << getID2<int>() << std::endl;
    std::cout << getID2<int>() << std::endl;
    std::cout << getID2<double>() << std::endl;
    std::cout << getID2<double>() << std::endl;
    std::cout << getID2<int>() << std::endl;

    return 0;
}

Output:

0
0
1
1
0
3 Answers

Each template call with its own type is its own function. Essentially, your code contains

int getID2_int() ..

and

int getID2_double() ..

as two separate functions. In each of these separate functions, you have

static int id2

which only gets initialized once, so getID gets called twice - once from the int version and once from the double version.

First of all, different template specializations are different functions, i.e., getID2<int> and getID2<double> are different functions.

When you first call getID2<int>(), you initialize a static variable

static int id2 = getID();

In turns, this calls getID(), which initializes a static int

 static int id = 0;

and returns i++. i++ is the post-increment of i, which means that getID() returns i (set to 0) and then increments i (to 1); because i is static, it will retain its value 1 on the next call of getID(). The returned value 0 is stored in the static variable id2 of getID2<int>.

When you call the second time getID2<int>, the initialization of id2 is skipped, and getID2<int> just returns its value 0.

Now, when you call getID2<double>, id2 gets initialized with the return value of getID(). This time, however, the static variable i of getID() is already initialized, and it equals 1. Hence getID() returns 1, and increments i to 2. The returned value 1 is passed to getID2<double>, which initializes its static int id2 variable to id2=1.

At the next call of getID2<double>, id2 is already initialized to 1, therefore getID2<double> just returns 1.

A static variable of a function is initialized only once when the function gets the control the first time.

So when the function specialization getID2<int> is called the first time

std::cout << getID2<int>() << std::endl;

its static variable id2 is initialized by the value of the static variable id of the non-template function by 0 (pay attention to that in the return statement of the non-template function there is used the post-increment operator

return id++;

So the returned value of the function is the value of the variable id before the increment.)

. So in the second call of the function template specialization

std::cout << getID2<int>() << std::endl;

the declaration

static int id2 = getID();

is skipped and the function again outputs 0.

The same is valid for the function template specialization getID2<double> but in this case in the first call of the function the value of id is already was changed to 1. So all calls of the specialization returns the initialized static variable id2 with the value 1.

std::cout << getID2<double>() << std::endl;

Again in subsequent calls of the specialization the declaration

static int id2 = getID();

is skipped because the static variable id2 was already initialized.

Pay attention to that specialization of a template function are different functions.

From the C++ 17 Standard (9.7 Declaration statement)

4 Dynamic initialization of a block-scope variable with static storage duration (6.7.1) or thread storage duration (6.7.2) is performed the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization....

Related