This is an example taken from geeksforgeeks. I don't understand the following code.
template<class T> int Test<T>::count = 0;
Is count an external variable? Why not just let static int count = 0?
The description and code in the geeksforgeeks is listed below.
Class templates and static variables: The rule for class templates is
same as function templates Each instantiation of class template has
its own copy of member static variables. For example, in the following
program there are two instances Test and Test. So two copies of static
variable count exist.
#include <iostream>
using namespace std;
template <class T> class Test
{
private:
T val;
public:
static int count;
Test()
{
count++;
}
// some other stuff in class
};
template<class T>
int Test<T>::count = 0;
int main()
{
Test<int> a; // value of count for Test<int> is 1 now
Test<int> b; // value of count for Test<int> is 2 now
Test<double> c; // value of count for Test<double> is 1 now
cout << Test<int>::count << endl; // prints 2
cout << Test<double>::count << endl; //prints 1
getchar();
return 0;
}
Every time you instantiate Test object with new type, a new class from available template is created for you. (So in your case, there Test<int> and Test<double> classes created on demand for you by the compiler). You can now think of Test<int> and Test<double> as 2 separate classes created from the same template.
Because there are two classes, there are two copies of static variable with same name in different scopes. template<class T> int Test<T>::count = 0; is a template for the definition of this count in classes created on demand.
If you specialize this definition for some type, for ex:
template<>
int Test<int>::count = 5;
Test<int>::count would be 7 at the time of print it. While Test<double>::count would remain 1 (unchanged).
count is not an external variable. The reason why it is outside the class like that is because the variable needs to be allocated (and maybe instantiated). When a static variable is inside a class definition, it only tells the compiler "there is going to be this kind of variable" but since definitions may be included in many source files the compiler won't do any allocations.
When the compiler sees the external definition it knows to allocate space for it and instantiate it if it is an object. This may happen only once, so it cannot be in a header file.
Class Test is a template class, meaning the compiler will generate different code each time it encounters code that instantiates a Test with a different type.
Count is not an external variable; it is a static variable.
There is one instance of a static variable shared by all instances of their container classes.
The twist here is that Test is a template class, so there is not really just one "class Test". There are two: the main() function will cause the compiler to generate "class Test" and "class Test".
As noted a static variable is shared by all instances of their container classes. As also noted, there are two generated types of class Test (int and double). Because count is a static variable, this means there needs to be one instance of count per type of Test. Therefore the compiler will generate both:
int Test<int>::count = 0;
and
int Test<double>::count = 0;
Keep in mind that the purpose of templates is that you write code once and rely on the compiler to generate code for all the different data types for which that template is used.
Related
Usually, we do declare but not define a global variable in the header file. However, we define templates in it. Then the issue arises: is it possible to define a global variable template?
template <uint8_t PinCode>
uint8_t BitMask = digitalPinToBitMask(PinCode);
In reality, a global variable template:
instantizes only if at least one compile unit (CU) requires it.
causes no redefinition errors if multiple CUs require the same instance.
is shared among CUs, i.e., if one CU changes the value of an instance, other CUs requiring the same instance will be affected.
calls the initializer only once for each kind of required instance.
After longer research, I finally found the most elegant solution. The definition style depends on whether you want to initialize the variable.
If the variable does not need initialization, you only need a header file:
template <int TimerCode>
int TCCRB;
Yes, it is and must be so simple. Don't add "static" or "extern" keywords like we usually do for variables in a header file. It will pass compilation and work as a global variable template among all CUs. Same instances will share the same actual variable, i.e., changes in one CU will affect other CUs, as long as they have the same template arguments.
As we know, if you define a variable with no necessary keywords like "static" or "extern" in a header file, it will cause a redefinition error if the header is included in more than one CUs. "static" tell the compiler to copy this variable for each CU as individual variables, so changes in one CU won't affect that in another CU. Instead, "extern" tells the compiler that this variable here is only a declaration. It's defined and owned in only one of the CUs, and other CUs should only keep a reference or symbol to it. So that changes in one CU WILL affect other CUs.
However, a variable template is neither a static definition nor an extern declaration. It's a special instruction to the compiler: find all cases of references to this template, combine those of the same template arguments, and generate one definition automatically for each unique instance! This time the compiler takes the responsibility to avoid redefinition: it scans all CUs and then generates unique definitions itself!
This automatic definition is so convenient if you don't want to give the variable an initial value, and if there are too many possible instances to be listed one by one. However, if you do want an initial value, you'll have to define it yourself, and you'll need an individual CU to own these variables to avoid redefinition:
//In the header file:
template <int TimerCode>
extern int TCCRA;
//In the CPP file:
template <>
int TCCRA<1> = 2;
template <>
int TCCRA<2> = 5;
//Naturally you have to provide initial values for all possible instances …
For this case, the "extern" keyword is necessary because you explicitly defined all valid instances in your specially provided CU, and other CUs must refer to this definition. The compiler shouldn't generate a random definition itself. This is very much like a normal global variable definition, only adding some template grammars. However, the user can only use instances provided in your CPP file. This is also very natural because only for known instances can you provide an initial value.
I found very few tutorials on this topic on the Internet. I hope my experience will help more people ~
The standard defines many global constants which are templatized such as the type traits type_trait_v constants.
They are defined as such in the header
template<class T>
inline constexpr some_type some_variable = ...;
In your example you could do something like
template<uint8_t Pin>
inline constexpr uint8_t BitMask = digitalPinToMask(Pin);
For this to work then digitalPinToMask must be invocable in a constexpr context.
(Not to be confused with C++11 Extern Templates)
Ok, so after a long while battling compilers and linkers, the best solution I came up with for declaring a global variable that is a template with extern linkage is:
// lib.hpp
#pragma once
namespace lib {
template <typename T>
struct _GlobalTemplateExternImpl {
std::array<T, 2> value;
};
template <typename T>
inline auto &global_template_value = _GlobalTemplateExternImpl<T>::value;
}
// lib.cpp
#include "lib.hpp"
template
struct lib::_GlobalTemplateExternImpl<int>;
template <>
std::array<int, 2> lib::_GlobalTemplateExternImpl<int>::value = {}; // NOTE: the assignment (`= {}`) is important to do
template
struct lib::_GlobalTemplateExternImpl<float>;
template <>
std::array<float, 2> lib::_GlobalTemplateExternImpl<float>::value = { 7.0f, 66.6f };
// main.cpp
#include "lib.hpp"
#include <iostream>
int main() {
using namespace lib;
std::cout << global_template_value<int>[0] << "\n";
std::cout << global_template_value<int>[1] << "\n";
std::cout << global_template_value<float>[0] << "\n";
std::cout << global_template_value<float>[1] << "\n";
return 0;
}
And since C++ needs silly acronyms, I shall dub this the "Implicitly Externed Template Global Pattern" (IETGP) since the keyword extern is nowhere to be found.
class Solution {
public:
static int m=INT_MIN; // it shows error: non-const static data member must
be initialized out of line.(why?)
using "int m=INT_MIN" is fine.
int func(TreeNode*root){
if(root==NULL){
return 0;
}
int l=max(func(root->left),0);
int r=max(func(root->right),0);
m=max(l+r+root->val,m);
return max(l,r)+root->val;
}
int maxPathSum(TreeNode* root) {
if(root==NULL)
{
return 0;
}
m=INT_MIN;
int x=func(root);
return m;
}
};
I need to update the value of variable m. Therefore I am using static int data type. But the following error is coming.
Using int instead of static int is working fine. But why is static int giving error?
Bjarne Stroustrup explains this here:
A class is typically declared in a header file and a header file is
typically included into many translation units. However, to avoid
complicated linker rules, C++ requires that every object has a unique
definition. That rule would be broken if C++ allowed in-class
definition of entities that needed to be stored in memory as objects.
As said by Stroustrup, every class needs a unique definition. Now, as we know static members are associated directly with their class. Now consider the two cases:
The static member is also constant, then its initialization is allowed inline because the compiler can make its own optimisations and treat this member as a compile-time constant because it is guaranteed that its value will never change. So, as the value of this member is fixed, the definition of the class with which this member is associated is also fixed. So, the initialization is allowed inline.
The static member is not constant. Then its value can change later on during the execution of the program. So, the compiler can not make compile-time optimisations on this member. Hence, to prevent the complications that may arise while trying to initialize such a member when the class is loaded, inline initialisation of such members is not allowed.
PS: When I heard about this concept the very first time, I was also confused because it is not in accordance with the principle of orthogonality that is a feature desired by programmers. The principle of orthogonality will state that since we can combine int and static; and int and const, we should be able to write static const int and static int in a similar fashion. But this case here is an example of a situation where the developer of a language has to give up orthogonality for the users of the language in exchange of the simplicity of the compilation process.
Have a look at the concept of orthogonality here
To answer OPs question why
class Solution {
public:
int m = INT_MIN;
};
is fine but
class Solution {
public:
static int m = INT_MIN;
};
is not:
In short: Prefixing a data-member with static fundamentally change its meaning.
Without static, the member variable is part of the class and each instance will provide a separate storage for this member variable.
With static, the member variable has only scope of the class but there will be only one global storage.
Respectively, the initialization has different meanings too.
For non-static member variables, it provides a default initialization which constructors may use (or override).
Demonstration by Example:
#include <iostream>
enum ArgCase1 { Case1 };
enum ArgCase2 { Case2 };
class Solution {
public:
int m = 123;
Solution() = default; // will use m(123) implicitly
Solution(ArgCase1) { } // will use m(123) implicitly
Solution(ArgCase2): m(456) { } // default of m ignored
};
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(Solution sol);
std::cout << "sol.m: " << sol.m << '\n';
DEBUG(Solution sol1(Case1));
std::cout << "sol1.m: " << sol1.m << '\n';
DEBUG(Solution sol2(Case2));
std::cout << "sol2.m: " << sol2.m << '\n';
}
Output:
Solution sol;
sol.m: 123
Solution sol1(Case1);
sol1.m: 123
Solution sol2(Case2);
sol2.m: 456
Live Demo on coliru
For static member variables, the initialization would be dangerous. Assuming that a class is declared in a header which is included multiple times, this would result in a violation of the One Definition Rule.
In former times, it was usual to declare the static member variable in the header but to define it in the .cpp-file (which represents the translation unit).
Expample:
solution.h:
#ifndef SOLUTION_H
#define SOLUTION_H
class Solution {
public:
static int m;
};
#endif // SOLUTION_H
solution.cc:
// header of this module:
#include "solution.h"
int Solution::m = 123;
Live Demo on coliru
Since C++17, a new alternative is available – using the keyword inline.
From cppreference.com – static members – Static data members
A static data member may be declared inline. An inline static data member can be defined in the class definition and may specify an initializer. It does not need an out-of-class definition
Example:
solution.h:
#ifndef SOLUTION_H
#define SOLUTION_H
class Solution {
public:
inline static int m = 123;
};
#endif // SOLUTION_H
Live Demo on coliru
The advantage is that there is no .cpp-file needed for this i.e. as it is the class Solution could be provided as header-only source.
Lest consider well-known compile time recursive fibonacci calculation. In this particular case how many times fibonacci<1> (or fibonacci<20> doesn't matter) was instantiated? Was it exactly once? If yes, compiler does dynamic programming algorithm for us :)
template<int n>
struct fibonacci
{
static const uint64_t value = fibonacci<n - 1>::value + fibonacci<n - 2>::value;
};
template<>
struct fibonacci<0>
{
static const uint64_t value = 0;
};
template<>
struct fibonacci<1>
{
static const uint64_t value = 1;
};
int main()
{
std::cout << fibonacci<80>::value;
}
Lets consider another example.
int main()
{
std::vector<int> v1;
std::vector<int> v2;
}
Does C++ compiler generate separate code code for both instances of vector<int>?
What if similar instances of vector<int> was in different translation units?
The C++ standard does not mandate one or the other. As long as the finished program behaves as specified, a compiler may do anything, see the so-called "as-if" rule (§1.9-1). A good compiler will not generate unnecessary code, so I would expect it to optimize the fibonacci example to a constant, and the vector example to one implementation of the vector functions.
You're relying on something called "implicit instantiation" here. Explicit template instantiation would be
template class fibonacci<0>;
template class fibonacci<1>;
template class fibonacci<2>;
// etc
Now, the possibility of explicit template instantiation allows you to turn off implicit instantiation:
extern template class fibonacci<0>;
extern template class fibonacci<1>;
extern template class fibonacci<2>;
// etc
Why is this relevant? It means the compiler already has a fairly refined mechanism to deal with template instantiations. For implicit instantiation to work, a compiler must necessarily be able to check on the instantiation status, so it won't implicitly instantiate templates that have been explicitly instantiated.
So, it follows that there is an "what's the instantiation status?" check. And that may return "already implicitly instantiated". It would be a pessimization to re-instantiate the template in that case!
In this particular case how many times fibonacci<1> (or fibonacci<20> doesn't matter) was instantiated?
Zero objects and only a static (const!) value.
With
std::vector<int> v1;
std::vector<int> v2;
are instantiated two objects.
Consider a class like so:
template < class T >
class MyClass
{
private:
static T staticObject;
static T * staticPointerObject;
};
...
template < class T >
T MyClass<T>::staticObject; // <-- works
...
template < class T >
T * MyClass<T>::staticPointerObject = NULL; // <-- cannot find symbol staticPointerObject.
I am having trouble figuring out why I cannot successfully create that pointer object.
The above code is all specified in the header, and the issue I mentioned is an error in the link step, so it is not finding the specific symbol.
"Cannot find symbol staticPointerObject" - this looks like a linker error message. Is it? (Details like this have to be specified in your question).
If it is, them most likely it happens because you put the definition(s) of your static member(s) into an implementation file (a .cpp file). In order for this to work correctly, the definitions should be placed into the header file (.h file).
Again, details like this have to be specified in your question. Without them it turns into a random guess-fest.
I suspect the reason your first example is the following (from the 2003 C++ std document). Note particularly the last sentence -- from your example, there seems to be nothing "that requires the member definition to exist".
14.7.1 Implicit instantiation [temp.inst] 1 Unless a class template specialization has been explicitly instantiated (14.7.2) or explicitly
specialized (14.7.3), the class template specialization is implicitly
instantiated when the specialization is referenced in a context that
requires a completely-defined object type or when the completeness of
the class type affects the semantics of the program. The implicit
instantiation of a class template specialization causes the implicit
instantiation of the declarations, but not of the definitions or
default arguments, of the class member functions, member classes,
static data members and member templates; and it causes the implicit
instantiation of the definitions of member anonymous unions. Unless a
member of a class template or a member template has been explicitly
instantiated or explicitly specialized, the specialization of the
member is implicitly instantiated when the specialization is
referenced in a context that requires the member definition to exist;
in particular, the initialization (and any associated side-effects) of
a static data member does not occur unless the static data member is
itself used in a way that requires the definition of the static data
member to exist.
Your first "definition" of static member is but a declaration - here is a quote from the standard.
15 An explicit specialization of a
static data member of a template is a
definition if the declaration includes
an initializer; otherwise, it is a
declaration. [Note: there is no syntax
for the definition of a static data
member of a template that requires
default initialization. template<> X
Q::x; This is a declaration
regardless of whether X can be default
initialized (8.5). ]
The second definition should work. Are you sure you have everything available in one compilation unit? What is teh exact text of error message?
The following compiles/runs with g++ - all in one file
#include <iostream>
template < class T >
class MyClass
{
public:
static T staticObject;
static T * staticPointerObject;
};
template < class T >
T MyClass<T>::staticObject;
template < class T >
T * MyClass<T>::staticPointerObject = 0;
int main(int argc, char **argv)
{
int an_int = 5;
MyClass<int>::staticPointerObject = &an_int;
std::cout << *MyClass<int>::staticPointerObject << std::endl;
char a_char = 'a';
MyClass<char>::staticPointerObject = &a_char;
std::cout << *MyClass<char>::staticPointerObject << std::endl;
}
I have found two solutions. Neither of them are 100% what I was hoping for.
Explicitely initialize the specific instance, e.g.
int * MyClass<int>::staticPointerObject = NULL;
This is not convinient especially when I have a lot of different types.
Wrap the pointer inside the class, e.g.
template < class T >
class MyClass
{
private:
struct PointerWrapper
{
T * pointer;
PointerWrapper( void )
: pointer( NULL )
{ }
};
T staticObject;
PointerWrapper staticPointerObject;
};
...
template < class T >
T MyClass<T>::staticObject; // <-- works fine.
...
template < class T >
MyClass<T>::PointerWrapper MyClass<T>::staticPointerObject; // <-- works fine.
This is a bit of a hassle, but at least usable. Why is it I can instansiate a variable object but not a pointer to a variable object? If anything I would think I'd have more problems the other way around (the compiler knows ahead of time what a pointer looks like, but not what my object looks like).
If someone has a better answer I'd love to see it!
I use the following trick all the time. The idea is to put your static in a function, and access it only from that function. This approach also allows you to avoid the need to declare your static in a .cpp file -- everything can live in the .h file. Following your example code:
template < class T >
class MyClass
{
public:
static T * getObject() {
// Initialization goes here.
static T * object = NULL; // or whatever you want
return pointerObject;
}
};
I have a template class defined in a header file like this. Here I have defined a static variable as well:
#ifndef TEST1_H_
#define TEST1_H_
void f1();
static int count;
template <class T>
class MyClass
{
public:
void f()
{
++count;
}
};
#endif
And I have defined main() function in a different cpp file like this:
int main(int argc, char* argv[])
{
MyClass<int> a;
a.f();
f1();
cout<<"Main:" << count << "\n";
return 0;
}
I have implemented function f1() in a different cpp file like this:
void f1()
{
MyClass<int> a;
a.f();
cout<<"F1: " <<count <<"\n";
}
When I compiled this using VC6, I got the output as "F1:0 Main:2". How is this possible? Also, in general how should I handle if I want to use static variables along with templates?
You're getting two copies of the same variable because you've declared a static variable in a header file. When you declare a global variable static this way, you're saying it's local to the compilation unit (the .o file). Since you include the header in two compilation units, you get two copies of count.
I think what you really want here is a static template member variable associated with each instance of the template class. It would look like this:
template <class T>
class MyClass
{
// static member declaration
static int count;
...
};
// static member definition
template<class T> int MyClass<T>::count = 0;
This will get you a count for each instantiation of your template. That is, you'll have a count for MyClass<int>, MyClass<foo>, MyClass<bar>, etc. f1() would now look like this:
void f1() {
MyClass<int> a;
a.f();
cout<<"F1: " << MyClass<int>::count <<"\n";
}
If you want a count for all instantiations of MyClass (regardless of their template parameters), you do need to use a global variable.
However, you probably don't want a global variable directly because you run the risk of using it before it gets initialized. You can get around this by making a global static method that returns a reference to your count:
int& my_count() {
static int count = 0;
return count;
}
Then accessing it from within your class like this:
void f() {
++my_count();
}
This will ensure that count gets initialized before it's used, regardless of which compilation unit you access it from. See the C++ FAQ on static initialization order for more details.
Putting the static declaration in a header file will cause each .cpp file to get its own version of the variable. So the two cout statements are printing different variables.
Were you expecting "F1:1 Main:1"? You instantiated MyClass<int> in two separate translation units (i.e. two object files), and the linker saw that there was a duplicate template instantiation, so it discarded the instantiation that was in f1's object file.
Are you passing /OPT:ICF or /OPT:REF to the VC6 linker? That might be related to the duplicate template instantiation removal (or not; duplicate template instantiations might be a special case, compared to ordinary duplicate functions). GCC seems to do something similar on some platforms.
Anyway, I wouldn't rely on this behavior being consistent across compilers. Also, changing the order of object files on the linker command line might affect which instantiation gets discarded.
There is another solution, you can create a shared parent class and put this static variable in it, then make your template class inherit it privately, here's an example:
class Parent
{
protected:
static long count;
};
long Parent::count = 0;
template<typename T>
class TemplateClass: private Parent
{
private:
int mKey;
public:
TemplateClass():mKey(count++){}
long getKey(){return mKey;}
}
int main()
{
TemplateClass<int> obj1;
TemplateClass<double> obj2;
std::cout<<"Object 1 key is: "<<obj1.getKey()<<std::endl;
std::cout<<"Object 2 key is: "<<obj2.getKey()<<std::endl;
return 0;
}
Output will be:
Object 1 key is: 0
Object 2 key is: 1
I think this is actually undefined behaviour.
According to C++14 [basic.def.odr]/6:
There can be more than one definition of a [...] member function of a class template [...] in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then
each definition of D shall consist of the same sequence of tokens; and
in each definition of D, corresponding names, looked up according to 3.4, shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution (13.3) and after matching of partial template specialization (14.8.3), except that a name can refer to a non-volatile
const object with internal or no linkage if the object has the same literal type in all definitions of D, and the object is initialized with a constant expression (5.19), and the object is not odr-used, and the object has the same value in all definitions of D; [...]
The problem is that in the first .cpp file, the name count within f1 refers to a different object than the name count within f1 in the second .cpp file, thus violating the condition that corresponding names should refer to the same entity.
They are different objects because of the static specifier which says that each translation unit gets its own object with that name.