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

时间:2015-01-15 13:29:12

标签: c++ templates c++11 inheritance singleton

我正在尝试使用静态成员实现模板类。从模板类派生的类应该被实例化,而不需要编写额外的代码。

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

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

是否可以通过从ConcreteA派生ConcreteA来强制实例化Singleton,而无需编写额外的实例化代码?

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

ConcreteA.c

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

有更好的解决方法吗?

4 个答案:

答案 0 :(得分:4)

基于您自己的&#34;脏技巧&#34;,这适用于我测试的所有编译器,并且不需要派生类构造函数中的任何代码:

#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的地址 - 使用它,迫使它存在。我必须说我并非100%确定在某些编译器的未来版本中我保证不会对其进行优化(我在所有地方使用-O2进行了测试)。

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

Singleton() { (void)&instance_; }

就足够了,完全摆脱了instptr_

答案 1 :(得分:2)

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

  

除非已明确实例化或明确实例化类模板或成员模板的成员   special,在引用特化时隐式实例化成员的特化   在需要成员定义存在的上下文中; 特别是初始化(以及任何相关的   除非静态数据成员本身以某种方式使用,否则不会发生静态数据成员的副作用   这需要存在静态数据成员的定义。

答案 2 :(得分:0)

以这种方式完成:

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

答案 3 :(得分:-2)

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

因为这样做,最好在函数内部实例化对象,而不是调用函数

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