对于静态成员初始化,我使用嵌套的helper结构,它适用于非模板化的类。 但是,如果封闭类由模板参数化,则如果未在主代码中访问辅助对象,则不会实例化嵌套初始化类。 为了说明,一个简化的例子(在我的例子中,我需要初始化一个向量)。
#include <string>
#include <iostream>
struct A
{
struct InitHelper
{
InitHelper()
{
A::mA = "Hello, I'm A.";
}
};
static std::string mA;
static InitHelper mInit;
static const std::string& getA(){ return mA; }
};
std::string A::mA;
A::InitHelper A::mInit;
template<class T>
struct B
{
struct InitHelper
{
InitHelper()
{
B<T>::mB = "Hello, I'm B."; // [3]
}
};
static std::string mB;
static InitHelper mInit;
static const std::string& getB() { return mB; }
static InitHelper& getHelper(){ return mInit; }
};
template<class T>
std::string B<T>::mB; //[4]
template<class T>
typename B<T>::InitHelper B<T>::mInit;
int main(int argc, char* argv[])
{
std::cout << "A = " << A::getA() << std::endl;
// std::cout << "B = " << B<int>::getB() << std::endl; // [1]
// B<int>::getHelper(); // [2]
}
使用g ++ 4.4.1:
[1]和[2]评论说:
A = Hello, I'm A.
按预期工作
[1]取消注释:
A = Hello, I'm A. B =
我希望,InitHelper初始化mB
A = Hello, I'm A. B = Hello, I'm B.按预期工作
因此我的问题:这是编译器错误还是坐在显示器和主席之间的错误? 如果是后者:是否有一个优雅的解决方案(即没有显式调用静态初始化方法)?
更新我:
这似乎是一种理想的行为(如ISO / IEC C ++ 2003标准14.7.1中所定义):
除非已经显式实例化或明确专门化了类模板或成员模板的成员,否则在需要成员定义存在的上下文中引用特化时,将隐式实例化成员的特化;特别是,除非静态数据成员本身以需要静态数据成员定义存在的方式使用,否则不会发生静态数据成员的初始化(以及任何相关的副作用)。
答案 0 :(得分:37)
答案 1 :(得分:4)
问题在于,您为静态成员变量提供的定义也是模板。
template<class T>
std::string B<T>::mB;
template<class T>
typename B<T>::InitHelper B<T>::mInit;
在编译期间,这实际上没有定义,因为T是未知的。它类似于类声明或模板定义,编译器在看到它时不会生成代码或保留存储。
当您使用模板类时,定义会在稍后隐式发生。因为在segfaulting案例中你不使用B&lt; int&gt; :: mInit,所以永远不会创建它。
解决方案将明确定义所需成员(不进行初始化):将某个源文件放入
template<>
typename B<int>::InitHelper B<int>::mInit;
这与显式定义模板类的方式基本相同。
答案 2 :(得分:2)
[1]未注释案例:
没关系。 static InitHelper B<int>::mInit
不存在。如果未使用模板类(struct)的成员,则不会编译它。
[1]和[2]未注释案例:
没关系。 B<int>::getHelper()
使用static InitHelper B<int>::mInit
和mInit
存在。
[1]评论说,[2]没有评论: 它在VS2008中适用于我。