This question already has answers here:
Why static variable needs to be explicitly defined?
(5 answers)
Closed 2 years ago.
So I have this file
template <typename T>
class TestStatic {
public:
static int staticVal;
};
//static member initialization
template<typename T> int TestStatic<T>::staticVal;
I don’t understand why I have to instantiate the Staticval isn’t it already instantiated in the class definition? Also does it generate a static variable for each template parameter types?
Thanks in advance.
This line:
static int staticVal;
inside the class is a declaration, not a definition. That's why you have to define it outside the class like this:
template<typename T>
int TestStatic<T>::staticVal = 0;
And yes, this will generate a definition of the member for all types T.
Alternatively, you could define the static variable inline, like this:
template <typename T>
class TestStatic {
public:
inline static int staticVal = 0;
};
which has the same semantics as above, but let's you avoid having to define the static variable separately outside the class.
As the variables declared as static are initialized only once as they are allocated space in separate static storage so, the static variables in a class are shared by the objects. There can not be multiple copies of the same static variables for different objects. Also because of this reason static variables can not be initialized using constructors.
Please refer for more information: Reference
Related
class TestClass
{
public:
static int testMember;
template<class T> static T* Foo()
{
//Defination....
}
}
//int TestClass::testMember; //Duplicate definition
Why can't I define a member field in .hpp while I can define member functions in .hpp?
Does it must be defined in a .cpp file?
Why can't I define a member field in .hpp
You can.
C++ doesn't care what you name your files, and doesn't care what extension the files have.
What you can't do is define the variable more than once. That would obviously violate the one definition rule.
In order to satisfy the one definition rule, you have two options:
In C++17 or later, make the variable inline.
class TestClass
{
public:
static inline int testMember;
template<class T> static T* Foo()
{
//Defination....
}
}
In any version of C++, place the definition in your code where it will be compiled exactly once.
Why ... [can I] define member functions in .hpp?
Because member functions, defined in the class, are implicitly inline. Just like your variable could be.
As Drew Dormann has mentioned, template member functions (static or not) are implicitly inline.
The same goes for class templates:
template <typename>
class TestClass
{
public:
static int testMember;
template<class T> static T* Foo()
{
//Definition....
}
};
// prior to C++17 you definition MUST be outside the class in the header
template <typename T>
int TestClass<T>::testMember{};
This question already has answers here:
static template functions in a class
(2 answers)
Closed 6 years ago.
I have a class MyClass
class MyClass
{
template <std::size_t N>
void MyFunc() { // Do something with N };
};
Then, is MyFunc a static or non-static member function?
It's a non-static member function template. If you declared it with static then it would be a static member function template.
MyFunc<0> is a non-static member function, so you would call it like so (assuming that you made it public):
MyClass c{};
c.MyFunc<0>();
In the following program "Here" is printed:
#include <iostream>
class Base
{
static bool temp;
static bool initTemp()
{std::cout<<"Here\n";return true;}
};
bool Base::temp = Base::initTemp();
class Derived : public Base
{};
int main() {int a;std::cin>>a;}
In the following program "Here" is not printed:
#include <iostream>
template <class T>
class Base
{
static bool temp;
static bool initTemp()
{std::cout<<"Here\n";return true;}
};
template <class T>
bool Base<T>::temp = Base<T>::initTemp();
class Derived : public Base<int>
{};
int main() {int a;std::cin>>a;}
In both cases Base is never referenced. The only difference is that in the second case it is a template class. Can anyone explain to me why this behavior occurs. I am using VS 2012.
In both cases Base is never referenced.
And that is precisely the reason why you see nothing being printed to the standard output.
The definition of a class template's static data member does not get instantiated unless you use that data member; like member functions, the definitions of static data members of a class template are instantiated on demand.
This is specified in paragraph 14.7.1/1 of the C++11 Standard:
[...] 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, scoped member enumerations, static data members and member templates. [...]
Since your client code never refers to Base<>::temp, there is no need to construct and initialize it.
As a side note, this signature:
void main()
Is not valid (standard) C++. If you want to write portable code, the return type of main() should always be int.
In the first case, you don't instantiate Base, but you do call the static function:
bool Base::temp = Base::initTemp();
In the second case, you never instantiate the template:
template <class T>
bool Base<T>::temp = Base<T>::initTemp();
You can explicitly instantiate the Base class template, as with:
template class Base<int>;
And then you will see "Here" printed.
You cannot create variable of undefined class, which you seem to do with line:
template <class T>
bool Base<T>::temp = Base<T>::initTemp();
You cannot allocate variable of undefined type. What you need is write something like:
Base<int>::temp = value;
of cause there will be different variable allocated for each type provided, so you cannot have common static variable for a template class. You'll have separate variable for each type you instantiate your template instead.
To downvoters here is complete example:
#include <iostream>
template<class T>
class X
{
public:
static int v;
};
template<class T>
int X<T>::v = 0;
int main()
{
X<int>::v = 3;
X<char>::v = 2;
using namespace std;
cout << X<char>::v << endl << X<int>::v;
}
It prints 2 3 which means you cannot have single variable for all classes you'll instantiate your template.
This question already has answers here:
C++ Static member initialization (template fun inside)
(3 answers)
How to force a static member to be initialized?
(6 answers)
Closed 9 years ago.
This question is hard to word, primarily because of the terms class instantiation vs. template instantiation. I have a template class that is full of static functions and members. Each specialization of this template needs to have some initialization done before it's first use.
My initial plan was to just give the template class a static initializer member, which will initialize the template class's static members during it's construction at dynamic initialization.
However, this isn't working. Unless I explicitly invoke code in the initializer class, the compiler won't generate any code or storage for it.
For example:
template<typename Tag>
class WorkerPool
{
struct WorkerInitializer
{
void foo() { }
WorkerInitializer() { WorkerPool<Tag>::start(); }
};
friend struct WorkerInitializer;
static WorkerInitializer _initializer;
static void start() { std::cout << "Started" << std::endl; }
public:
static void async() { std::cout << "Async" << std::endl; }
};
template<typename T> typename WorkerPool<T>::WorkerInitializer
WorkerPool<T>::_initializer;
struct GenericWorker { };
int main()
{
WorkerPool<GenericWorker>::async();
}
The output is just 'Async'.
However, if I change it so that calling WorkerPool<T>::async() calls _initializer.foo(), then the initializer does get compiled and correctly constructed, as I would expect.
Why is the compiler refusing to generate code for my static member?
I've tested with Visual Studio 2010/2012, gcc, and clang, and all produce the same result; my static member is not constructed. This makes me think that the standard requires this behavior, but I'm having trouble understanding why this might be.
What is the best way to have a static member in a non-templated library class,
without placing the burden of defining the member on the class user?
Say I want to provide this class:
class i_want_a_static_member
{
static expensive_resource static_resource_;
public:
void foo()
{
static_resource_.bar();
}
};
Then the user of the class must not forget to define the static member somewhere
(as already answered many times):
// this must be done somewhere in a translation unit
expensive_resource i_want_a_static_member::static_resource_;
I do have an answer below, but it has some disadvantages. Are there better and/or more elegant solutions?
C++17 and above
Use inline static variables for non-dynamic initialization:
struct Foo
{
inline static int I = 0;
};
And use function local static variables otherwise:
struct Foo
{
static std::string& Bar()
{
static std::string S = compute();
return S;
}
};
C++14 and below
Use function local statics, as they are plain easier to use.
If for some reason you really wish for a static data member, then you can use the template trick:
template <typename T = void>
struct Foo
{
static int I = 0; // inline initialization only for simple types.
};
template <typename T>
int Foo<T>::I;
On local statics
For resources which require dynamic initialization, it is best to use a local static.
The order in which file-scope or class-scope statics are dynamically initialized is undefined, in general, leading to the Static Initialization Order Fiasco when you try to read a uninitialized static as part of the initialization of another. Local static solve the issue by being initialized lazily, on first use.
There is some slight overhead to using local statics, however. From C++11 onwards, the initialization is required to be thread-safe, which typically means that any access is gated by an atomic read and well-predicted branch.
My own solution is to use a templated holder class, as static members work fine in templates, and use this holder as a base class.
template <typename T>
struct static_holder
{
static T static_resource_;
};
template <typename T>
T static_holder<T>::static_resource_;
Now use the holder class:
class expensive_resource { /*...*/ };
class i_want_a_static_member : private static_holder<expensive_resource>
{
public:
void foo()
{
static_resource_.bar();
}
};
But as the name of the member is specified in the holder class, you can't use the same holder for more than one static member.
As of C++ 17. You can now use inline variables to do this:
static const inline float foo = 1.25f;