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?
C++ Templates Explicit instantiation An explicit instantiation definition creates and declares a concrete class, function, or variable from a template, without using it just yet. An explicit instantiation can be referenced from other translation units.
The static member is declared or defined inside the template< … > class { … } block. If it is declared but not defined, then there must be another declaration which provides the definition of the member.
Implicit instantiation means that the compiler automatically generates the concrete function or class for the provided template arguments. In general, the compiler also deduces the template arguments from the function's arguments. In C++17, the compiler can also deduce the template arguments for class templates.
Definition. As per the standard definition, a template class in C++ is a class that allows the programmer to operate with generic data types. This allows the class to be used on many different data types as per the requirements without the need of being re-written for each type.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With