Static variable inside template function

2019-01-22 12:19发布

In C++, if you define this function in header.hpp

void incAndShow()
{
  static int myStaticVar = 0;
  std::cout << ++myStaticVar << " " << std::endl;
}

and you include header.hpp in at least two .cpp files. Then you will have multiple definition of incAndShow(). Which is expected. However, if you add a template to the function

template <class T>
void incAndShow()
{
  static int myStaticVar = 0;
  std::cout << ++myStaticVar << " " << std::endl;
}

then you won't have any multiple definition of error. Likewise, two different .cpp calling the function with the same template (e.g. incAndShow<int>()), will share myStaticVar. Is this normal? I'm asking this question, because I do rely on this "feature" (sharing the static variable) and I want to be sure that it is not only my implementation that is doing this.

7条回答
【Aperson】
2楼-- · 2019-01-22 12:46

Yes, it is "normal", but whatever you try to achieve with this "feature" maybe questionable. Try explain why you want to use local static variable, may be we can come up with a cleaner way to do it.

The reason this is normal is because of the way template functions are compiled and linked. Each translation unit (the two .cpp in your case) gets see their own copy of incAndShow and when the program is linked together, the two incAndShow will be merged into one. If you declare your regular function inline in the header file, you'll get similar effect.

查看更多
看我几分像从前
3楼-- · 2019-01-22 12:48

Take this example that shows the behaviour is absolutely expected:

#include <iostream>

template <class T> class Some
{
public:
   static int stat;
};

template<class T>
int Some<T>::stat = 10;

void main()
{
   Some<int>::stat = 5;
   std::cout << Some<int>::stat   << std::endl;
   std::cout << Some<char>::stat  << std::endl;
   std::cout << Some<float>::stat << std::endl;
   std::cout << Some<long>::stat  << std::endl;
}

You get: 5 10 10 10 10

The above shows that the change in static variable is only for type "int" and hence in your case you don't see any problem.

查看更多
Anthone
4楼-- · 2019-01-22 12:49

Just so i understand your question. You are asking if it is normal for each version of the templated function to have its own instance of myStaticVar. (for example: incAndShow<int> vs. intAndShow<float> The answer is yes.

Your other question is, if two files include the header containing the template function, will they still share the static variable for a given T. I would say yes.

查看更多
你好瞎i
5楼-- · 2019-01-22 12:53
  • templates will only actually be turned into code once they're instantiated (i.e. used)
  • headers are not to be used for implementation code, but only for declarations
查看更多
【Aperson】
6楼-- · 2019-01-22 12:56

The difference when you create the function template is that it has external linkage. The same incAndShow will be accessible from all translation units.

Paraphrasing from C++ standard working draft N2798 (2008-10-04): 14 part 4: a non member function template can have internal linkage, others always have external linkage. 14.8 point 2: every specialization will have its own copy of the static variable.

Your function template should have external linkage unless you declare it in the unnamed namespace or something. So, for each T that you use with your function template, you should get one static variable used throughput the program. In other words, it's OK to rely on having only one static variable in the program for each instantiation of the template (one for T==int, one for T==short, etc).

As an aside, this can lead to weird situations if you define incAndShow differently in different translation units. E.g., if you define it to increment in one file and the decrement in another file (without specifying internal linkage by putting the function into the unnamed namespace) both will end up sharing the same function, which will effectively be chosen at random at compile time (with g++ it depends on the order the object files are given on the command line).

查看更多
聊天终结者
7楼-- · 2019-01-22 13:02

Templates are instantiated as needed, which means that compiler (linker as well in this case?) will make sure that you don't end up with multiple instances of the same template as well as only those instances of templates that you need - in your case only incAndShow<int>() is instantiated and nothing else (otherwise compiler would have to try to instantiate for every type which does not make sense).

So I assume that the same methods it uses to figure out for which type to instantiate template prevents it from instantiating twice for the same type e.g. only one instance of incAndShow<int>()

This is different from non template code.

查看更多
登录 后发表回答