Static Variable Used in a Template Function

Static variable inside template function

You can rely on this. The ODR (One Definition Rule) says at 3.2/5 in the Standard, where D stands for the non-static function template (cursive font by me)

If D is a template, and is defined in more than one translation unit, then the last four requirements from the list above shall apply to names from the template’s enclosing scope used in the template definition (14.6.3), and also to dependent names at the point of instantiation (14.6.2). If the definitions of D satisfy all these requirements, then the program shall behave as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.

Of the last four requirements, the two most important are roughly

  • each definition of D shall consist of the same sequence of tokens
  • names in each definition shall refer to the same things ("entities")

Edit

I figure that this alone is not sufficient to guarantee that your static variables in the different instantiations are all the same. The above only guarantees that the multiple definitions of the template is valid. It doesn't say something about the specializations generated from it.

This is where linkage kicks in. If the name of a function template specialization (which is a function) has external linkage (3.5/4), then a name that refers to such a specialization refers to the same function. For a template that was declared static, functions instantiated from it have internal linkage, because of

Entities generated from a template with internal linkage are distinct from all entities generated in other translation units. -- 14/4

A name having namespace scope (3.3.6) has internal linkage if it is the name of [...] an object, reference, function or function template that is explicitly declared static -- 3.5/3

If the function template wasn't declared with static, then it has extern linkage (that, by the way, is also the reason that we have to follow the ODR at all. Otherwise, D would not be multiply defined at all!). This can be derived from 14/4 (together with 3.5/3)

A non-member function template can have internal linkage; any other template name shall have external linkage. -- 14/4.

Finally, we come to the conclusion that a function template specialization generated from a function template with external linkage has itself external linkage by 3.5/4:

A name having namespace scope has external linkage if it is the name of [...] a function, unless it has internal linkage -- 3.5/4

And when it has internal linkage was explained by 3.5/3 for functions provided by explicit specializations, and 14/4 for generated specializations (template instantiations). Since your template name has external linkage, all your specializations have external linkage: If you use their name (incAndShow<T>) from different translation units, they will refer to the same functions, which means your static objects will be the same in each occasion.

Static variable used in a template function

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).

static variable in variadic template function

Each specialization of the function gets its own copy of the static variable.



Does the compiler create a separate function for each function invocation?

Rather, for each used set of template arguments.

How to implement static variable functionality for templates in C++

This is a false premise:

However for templates I can't have just one static variables for all template instances.

Yes you can:

#include <iostream>

struct Base {
static int counter;
Base() { counter++; }
};

int Base::counter = 0;

template <typename T>
struct Foo : Base {};

int main(int argc, char** argv) {
Foo<int> x;
Foo<double> y;
Foo<float> z;
std::cout << Base::counter;
}

Output:

3

Actually this isn't something specific to your current problem. In general anything not depending on the template parameter can be moved to a non-template base class.

C++ static variable initialization inside a template function

The literal "one" is a const char [4].

this code:

test("one")

would ideally like to call test(const char (&)[4])

This works for test(const T&) (because const char (&) [4] can bind to const char (const&) [4]).

But it cannot work for test(T t) because you can't pass string literals by value. They are passed by reference.

However, const char[4] can decay to const char*, which can match template<class T> void func(T t).

The proof is in the pudding:

#include <cstdint>
#include <iostream>
#include <typeinfo>

template <typename T, std::size_t N>
void test_const(const T(&t)[N])
{
std::cout << __func__ << " for literal " << t << " T is a " << typeid(T).name() << " and N is " << N << std::endl;
}

template <typename T>
void test_mutable(T &t)
{
std::cout << __func__ << " for literal " << t << " T is a " << typeid(T).name() << std::endl;
}

template <typename T>
void test_const_ref(const T &t)
{
std::cout << __func__ << " for literal " << t << " T is a " << typeid(T).name() << std::endl;
}

template <typename T>
void test_copy(T t)
{
std::cout << __func__ << " for literal " << t << " T is a " << typeid(T).name() << std::endl;
}

int main()
{
test_const("one");
test_const("three");
test_mutable("one");
test_mutable("three");
test_const_ref("one");
test_const_ref("three");
test_copy("one");
test_copy("three");
}

example results (clang):

test_const for literal one T is a c and N is 4
test_const for literal three T is a c and N is 6
test_mutable for literal one T is a A4_c
test_mutable for literal three T is a A6_c
test_const_ref for literal one T is a A4_c
test_const_ref for literal three T is a A6_c
test_copy for literal one T is a PKc
test_copy for literal three T is a PKc

Here is a version with demangled names (will compile on clang and gcc):

#include <cstdint>
#include <iostream>
#include <typeinfo>
#include <cstdlib>
#include <cxxabi.h>

std::string demangle(const char* name)
{
int status = -1;
// enable c++11 by passing the flag -std=c++11 to g++
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};

return (status==0) ? res.get() : name ;
}

template <typename T, std::size_t N>
void test_const(const T(&t)[N])
{
std::cout << __func__ << " for literal " << t << " T is a " << demangle(typeid(T).name()) << " and N is " << N << std::endl;
}

template <typename T>
void test_mutable(T &t)
{
std::cout << __func__ << " for literal " << t << " T is a " << demangle(typeid(T).name()) << std::endl;
}

template <typename T>
void test_const_ref(const T &t)
{
std::cout << __func__ << " for literal " << t << " T is a " << demangle(typeid(T).name()) << std::endl;
}

template <typename T>
void test_copy(T t)
{
std::cout << __func__ << " for literal " << t << " T is a " << demangle(typeid(T).name()) << std::endl;
}

int main()
{
test_const("one");
test_const("three");
test_mutable("one");
test_mutable("three");
test_const_ref("one");
test_const_ref("three");
test_copy("one");
test_copy("three");
}

expected output:

test_const for literal one T is a char and N is 4
test_const for literal three T is a char and N is 6
test_mutable for literal one T is a char [4]
test_mutable for literal three T is a char [6]
test_const_ref for literal one T is a char [4]
test_const_ref for literal three T is a char [6]
test_copy for literal one T is a char const*
test_copy for literal three T is a char const*

Static Local Variable of a Template `inline` Function

The following article should answer you question very well: http://www.geeksforgeeks.org/templates-and-static-variables-in-c/

In short: The Compiler produces one static variable for each template.

If you want to have the same variable for all templates you can maybe try something like this:

int& hack()
{
static int i = 10;
return i;
}

template <typename T>
void fun(const T& x)
{
int &i = hack();
cout << ++i;
return;
}


Related Topics



Leave a reply



Submit