派生 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_
。
我正在尝试使用静态成员实现模板 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_
。