Why can't I define a static class member field in .hpp? - c++

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{};

Related

Explicit class member instantiation

I have created an ordinary class with a templated method, and all the method instances are explicit and inlined.
Like
class MyClass
{
template<int N> inline void MyMethod();
template<> inline void MyMethod<1>() { cout << 1; }
template<> inline void MyMethod<2>() { cout << 2; }
};
I needed to use the template<> syntax to have it compile. I tried other solutions, such as the explicit definition of the method outside the class declaration, with syntax variants, to no avail. (This was made under VS2008, not tried on later versions.)
I have two questions:
is this portable ?
does it make sense ?
The way you wrote it is wrong and it won't work.
Member method specializations must be put out of your class:
class MyClass
{
template<int N> void MyMethod();
};
template<> void MyClass::MyMethod<1>() { }
template<> void MyClass::MyMethod<2>() { }
It's portable and if it makes sense mostly depends on your actual problem, it's hard to say from your example.
You can't fully specialize member template in class body. Partial specialization are allowed though. Full specializations must be declared/defined outside class body (and definitions should be placed in cpp file if not declared inline).
For reference, this question.

How to inherit template abstract class with a class with template secification

I have a project on linux that builds into static library, which then I want to include in unit test project and in app project.
In this library I have something like that:
template<class T> class A
{
public:
virtual T doStuff() = 0;
virtual void doOther(T a) = 0;
protected:
A() { ... }
};
class B : public A<int>
{
public:
B() { ... }
virtual int doStuff() { ... }
virtual void doOther(int a) { ... }
};
I am getting compilation error: undefined reference to A<int>::A() in my lib.
I'm guessing it has something to do with template generation, and also can I override virtual functions like that?
templates are generated during compile time and needs to be implemented in the same translation unit they are prototyped. So, if you are including a declaration of a templated class, you also need to include the definition.
So, it would be prudent to have both the declaration and definition in the same header file, so that, any module that intends to use it, when compiled can generate the definition as required.
Refer:
14.7.2 Explicit instantiation [temp.explicit]
For a given set of template arguments, if an explicit instantiation of
a template appears after a declaration of an explicit specialization
for that template, the explicit instantiation has no effect.
Otherwise, for an explicit instantiation definition the definition of
a function template, a member function template, or a member function
or static data member of a class template shall be present in every
translation unit in which it is explicitly instantiated.

C++ static variables of unreferenced class

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.

How to have static data members in a header-only library?

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;

static initialization of Template classes for singleton object

We have a singleton template class as defines below
template<class T> class Singleton{
T& reference(){
return objT;
}
private:
T objT;
};
And another user defined class which uses this singleton
class TestClass{
static Singleton<TestClass> instance;
static TestClass * getPointer()
{
return &instance.objT;
}
private:
TestClass(){}
};
template<TestClass>
Singleton<TestClass> TestClass::instance;
On compilation with GCC we are getting the error
In function static_initialization_and_destruction undefined reference to Singleton::Singleton().
What can be the reason for this.
Ignoring the fact, that in your example there is no need for Singleton template, consider this simplified example (I am using structs to avoid access issues):
template <class T>
struct Singleton
{
T object;
};
struct TestClass;
typedef Singleton<TestClass> TCS;
TCS test1; // not ok, no definition of TestClass available;
struct TestClass
{
TestClass(){}
static TCS test2; // not ok, no definition of TestClass available;
};
TCS test3; // ok, TestClass is defined;
To declare a member of type T, you need a complete definition of this type T. So, test1 and test2 are not legal - there is only a declaration, not definition of T. On the contrary, test3 is legal - it is located after the complete definition of the class. Easiest fix here is to use pointer to type - to declare a pointer to type T, you need a declaration instead of definition for the type T:
template <class T>
struct Singleton
{
T * object;
};
static Singleton<TestClass> instance;
you are actually trying to create an instance of class Singleton in above line; which will look for default constructor Singleton() (which is already present as you haven't explicitly defined it private).
T& reference() is a private method in your class.
And I didn't really understand this
template<TestClass>
Singleton<TestClass> TestClass::instance;
Are you sure what you are trying to do? Cause am not ;)
Maybe you want to read this to understand what you are doing http://www.yolinux.com/TUTORIALS/C++Singleton.html
Easiest fix: Don't use a singleton.