派生 class 中的显式模板静态成员实例化

Explicit template static member instantiation in a derived class

我正在尝试使用静态成员实现模板 class。从模板 class 派生的 类 无需编写额外代码即可实例化。

这是我天真的(但不成功)的方法:

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

有没有一种方法可以通过从 Singleton 派生 ConcreteA 而无需编写额外的实例化代码来强制实例化 ConcreteA

一个肮脏的解决方法是在ConcreteA构造函数中调用instance_上的一个方法,例如:

ConcreteA.c

ConcrereA::ConcreteA { instance_.foo(); }

是否有更好的解决方法?

在 C++ 中,只要调用了定义实例的文件中的代码,就保证初始化静态对象(不保证初始化的顺序)。

因此,最好在函数中实例化对象,而不是调用函数

class A{
public:
    static A& getInstance(){
       static A a;
       return a;
    }
protected:
    A(){
    }
};

不幸的是,这是不可能的。引用C++11 14.7.1/2(谈模板的隐式实例化):

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.

这样做的:

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

建立在你自己的 "dirty trick" 上,这适用于我测试过的所有编译器,并且不需要派生的 class 构造函数中的任何代码:

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

我的理解是取instance_odr-uses地址,强制存在。我必须说我不是 100% 确定这在某些编译器的未来版本中不会被优化(我在任何地方都用 -O2 测试过它)。

编辑:看起来甚至像这样编写基础 class 构造函数

Singleton() { (void)&instance_; }

就够了,完全摆脱了 instptr_