4

I am not able to understand the output of the below code:-

#include <iostream>
using namespace std;
template <typename T>
void fun(const T&x){
 static int count = 0;
 cout << "x = " << x << " count = " << count << endl;
 ++count;
 return;
}
int main(){
 fun(1);
 fun('A');
 fun(1.1);
 fun(2.2);
 return 0;
}
Output:-
x = 1 count = 0
x = A count = 0
x = 1.1 count = 0
x = 2.2 count = 1

If value of static variable count is being reassigned to 0 whenever the function is called, then why its coming 1 when the function is being called fourth time. And another thing , can we not pass "T x" directly instead of "const T&x"?

  • `T x` vs `const T& x` is a [question](https://stackoverflow.com/questions/2582797/why-pass-by-const-reference-instead-of-by-value) that has gotten a lot of attention over the years. Essentially boils down to "making a copy is sometimes more expensive, but sometimes making a reference is more expensive". – Nathan Pierson Jun 20 '21 at 16:59
  • Related: [Static Local Variable of a Template \`inline\` Function](https://stackoverflow.com/q/30581479) has an answer that uses a separate non-template function as a way to have separate templates all access the same static variable. Or make it global, perhaps in a namespace, if it can be statically initialized. – Peter Cordes Jul 28 '22 at 00:14

3 Answers3

7

When a template gets instantiated, with explicit or deduced template parameters, it's as if a completely new, discrete, class or function gets declared. In your case, this template ends up creating three functions:

void fun<int>(const int &x)

void fun<char>(const char &x)

void fun<double>(const double &x)

It's important to understand that each one of these is a separate, standalone function, with its own static count variable. Because it's static, it gets initialized once, and its value is preserved across function calls. That's how static variables work in functions.

The shown code calls the first two once, and the third one twice. Those are the results you are seeing (the 2nd call to the third function incremented the same static count again).

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
5

Templates in C++ aren't generic functions like they are in Java. They're more like cookie cutters that make a new type-specific function for each type used to instantiate them. Your code is basically equivalent to this:

#include <iostream>
using namespace std;
void fun_int(const int&x){
 static int count = 0;
 cout << "x = " << x << " count = " << count << endl;
 ++count;
 return;
}
void fun_char(const char&x){
 static int count = 0;
 cout << "x = " << x << " count = " << count << endl;
 ++count;
 return;
}
void fun_double(const double&x){
 static int count = 0;
 cout << "x = " << x << " count = " << count << endl;
 ++count;
 return;
}
int main(){
 fun_int(1);
 fun_char('A');
 fun_double(1.1);
 fun_double(2.2);
 return 0;
}

And now it's obvious that you don't just have one static variable, but rather three different ones in different functions that just happen to have the same name.

4

If value of static variable count is being reassigned to 0 whenever the function is called...

That's where you're wrong. A static variable with an initializer (irrespective of its scope) is set to the value of the initializer once and once only. For static variables declared globally (in file scope), that initialization will be at program start-up; for static data declared in functions (as yours are), that initialization is deferred to the first time the function's code is executed.

Your code defines three different overloads of fun, each of which has its own copy of the local count variable. When the overload with the double argument is called the second time, the count variable will not be reinitialized – just incremented.

From this Draft C++17 Standard:

6.8.3.2 Static initialization     [basic.start.static]
1    Variables with static storage duration are initialized as a consequence of program initiation. …

and, for locally-declared static variables, we have this:

9.7 Declaration statement     [stmt.dcl]

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

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • 1
    A static variable **in a function** is initialized the first time that execution reaches the definition of that variable. If the function is never called, the variable is never initialized (conceptually). That's important when the variable has an expensive initializer -- lazy initialization means not initializing it unless it's actually used. – Pete Becker Jun 20 '21 at 17:43
  • @PeteBecker That's actually what I thought. But the only reference I can find in the Draft I quoted is for *destruction* of locally-scoped static objects (which does, itself, imply what you have asserted). – Adrian Mole Jun 20 '21 at 17:47
  • It's [stmt.dcl/4](https://eel.is/c++draft/stmt.dcl). – Pete Becker Jun 20 '21 at 19:09
  • @PeteBecker Thanks. I've added the relevant section (different number, same text) from the Draft I originally quoted. (I'll need to start using that website, instead...) – Adrian Mole Jun 20 '21 at 19:29
  • Re: "different number" -- that's why we use the tag names, here [stmt.dcl], instead of the section numbers. They're consistent (absent major reorganization of a section) and searchable, too. – Pete Becker Jun 20 '21 at 20:25
  • @Pete Yeah ... I'm on a journey of learning. Still far from the end of the road. :) I shall start using tags when quoting the Standard. – Adrian Mole Jun 20 '21 at 20:26