Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explicit template static member instantiation in a derived class

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?

like image 946
sergej Avatar asked Jan 15 '15 13:01

sergej


People also ask

What is explicit template instantiation?

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.

What happens when there is static member in a template class function?

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.

What is implicit instantiation?

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.

What is a template class?

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.


1 Answers

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.

like image 115
bogdan Avatar answered Sep 28 '22 08:09

bogdan