I am trying to implement a template class with a static member. Classes that are derived from the template class shall be instantiated without the need to write extra code.
Here is my naive (and not successful) approach:
Singleton.h:
template <class T> class Singleton {
protected:
Singleton();
static T instance_;
}
// explicit instantiation of 'instance_' ???,
// where 'instance_' is an instance of the derived class
template <class T> T Singleton<T>::instance_;
ConcreteA.h:
class ConcreteA : public Singleton<ConcreteA> {
public:
ConcreteA();
void foo();
}
main.c:
int main() {
// an instance of ConcreteA should have been created (no extra code)!!!
return 0;
}
Is there a way to force the instantiation of ConcreteA
by just deriving ConcreteA
from Singleton
, without writing extra instantiation code?
A dirty workaround is to call an method on instance_
in the ConcreteA
constructor, for example:
ConcreteA.c
ConcrereA::ConcreteA { instance_.foo(); }
Are there better workarounds?
Building upon your own "dirty trick", this works in all the compilers I tested, and doesn't require any code in the derived class constructor:
#include <iostream>
template <class T> class Singleton {
protected:
Singleton() { instptr_ = &instance_; }
static T instance_;
private:
static T* instptr_;
};
template<class T> T Singleton<T>::instance_;
template<class T> T* Singleton<T>::instptr_;
class ConcreteA : public Singleton<ConcreteA> {
public:
ConcreteA() { std::cout << "ConcreteA constructed.\n"; }
void foo();
};
int main() {
//Prints 'ConcreteA constructed.'.
return 0;
}
My understanding of it is that taking the address of instance_
odr-uses it, forcing it into existence. I must say I'm not 100% sure this is guaranteed not to be optimized away in future versions of some compiler (I tested it with -O2
everywhere).
EDIT: Looks like even writing the base class constructor like this
Singleton() { (void)&instance_; }
is enough, which gets rid of instptr_
altogether.
Unfortunately, that is not possible. Quoting C++11 14.7.1/2 (talking about implicit instantiation of templates):
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.
it's done this way:
template <class T> class Singleton {
protected:
Singleton();
// note: static function contains static variable
static T& instance() {
static T _t; // c++11 guarantees that this is thread-safe
return _t;
}
}
class ConcreteA : public Singleton<ConcreteA>
{
...
};
auto& myA = ConcreteA::instance();
In C++ static object are guarantee to initialize just if a code from the file that the instance is defined has been called (The order of the initialization is not guarantee).
because of this it better do instance the object inside a function and than call the function
class A{
public:
static A& getInstance(){
static A a;
return a;
}
protected:
A(){
}
};