Explicit template static member instantiation in a

2020-04-06 05:58发布

问题:

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?

回答1:

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.



回答2:

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.



回答3:

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();


回答4:

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