有很多关于何时调用普通类的静态成员的构造函数的信息。但是,我看到一些关于模板类的奇怪行为。
以下程序的输出应该是什么? (注意我使用printf来避免任何静态初始化命令与std :: cout的混淆并发症。)
#include <iostream>
class B {
public:
B(const std::string &s) { printf("Hello I am B from %s\n", s.c_str()); }
};
template<typename T>
class Atempl {
public:
static B b_;
};
class A {
public:
static B b_;
};
template<typename T>
B Atempl<T>::b_("Atempl");
B A::b_("A");
class C : public Atempl<int> {
};
int main(int argc, const char *argv[]) {
return 0;
}
我认为输出应该是:
Hello I am B from A
Hello I am B from Atempl
但是使用FreeBSD 7.3上的g ++ 4.3,我得到了:
Hello I am B from A
如果我添加行
template class Atempl<int>;
一切都很好,我得到了预期的输出。问题是,为什么C类的声明不算作模板的实例化 Atempl 并导致B的构造函数被调用?这是标准的一部分还是g ++ 4.3中的错误?
答案 0 :(得分:10)
在类模板中,执行隐式实例化时,会根据需要实例化成员。由于代码不使用静态成员,因此甚至不在整个应用程序中实例化。
当你进行显式的实例化时,整个类及其所有成员都会被实例化,并且包含静态成员变量,然后对其进行初始化并获得预期的结果。
如果没有显式实例化,您可以执行B* p = &Atempl<int>::b_;
(或静态成员的任何其他用法)来触发实例化。
答案 1 :(得分:3)
当初始化类模板模板的静态成员时 不确定的。实际上,除非你实际使用静态成员,否则它 不应该实例化,所以永远不要初始化。如果你 显式实例化模板,强制实例化所有 成员,反过来强制初始化(但我认为 究竟什么时候它将被初始化仍未指定。)
答案 2 :(得分:0)
在进程开始后和调用main()
之前的某个时间,它们由C ++运行时调用。 “常规”类和类模板实例之间没有区别。调用构造函数的顺序是未定义的。