我想构建一个仅包含静态数据成员和函数的模板类,基本上是带有一些内部数据的函数集合,我想填充代码的各个部分。我试图在到达 main()
之前将内容插入数据成员中。这对于非模板类来说效果很好,但对于模板类我似乎不知道如何让它工作。
代码如下:
#include <iostream>
#include <vector>
class Foo{
private:
static std::vector<unsigned> content;
public:
static void insert(unsigned u){ content.push_back(u); }
static size_t size(){ return content.size(); }
};
std::vector<unsigned> Foo::content=std::vector<unsigned>();
struct Bar{
Bar(){ Foo::insert(0); }
} bar;
// this works fine in gcc, but is this consistent or am I lucky?
// Foo::content will contain 0 prior to entering main
template <typename T>
class Quux{
private:
static std::vector<T> content;
public:
static void insert(T t){ content.push_back(t); }
static size_t size(){ return content.size(); }
};
template <typename T>
std::vector<T> Quux<T>::content=std::vector<T>();
struct Wobble{
Wobble(){ Quux<unsigned>::insert(0); }
} wobble;
// this does not work
// Quux<unsigned>::content will be empty prior to entering main
int main(){
std::cout << Foo::size() << std::endl;
// outputs 1, as desired
std::cout << Quux<unsigned>::size() << std::endl;
// outputs 0, makes me sad :(
Wobble wobble2;
std::cout << Quux<unsigned>::size() << std::endl;
// outputs 1, as desired
}
输出:
1
0
1
Foo
是非模板类,我可以在 Foo::content
中插入内容运行之前main()
通过结构Bar
正好。我希望这是一贯的行为而不是我运气好?
当我尝试对模板类执行相同的操作时 Quux<T>
不过,看来还得等到main()
在我可以添加东西之前。有人可以解释为什么这是必要的以及(希望)解决这个问题的方法吗?我认为这与模板实例化的时间有关,但我无法弄清楚到底为什么。我期望 Quux<unsigned>
在以下情况后完全可用:
struct Wobble{
Wobble(){ Quux<unsigned>::insert(0); }
} wobble;
我在这里缺少什么?为什么我可以在 main
之前向非模板化类添加内容通过bar
但我不能通过 wobble
做同样的事情吗? ?有没有办法获得与Foo
中相同的行为和Bar
使用模板类?
最佳答案
[basic.start.init]/2
Definitions of explicitly specialized class template static data members have ordered initialization. Other class template static data members (i.e., implicitly or explicitly instantiated specializations) have unordered initialization. [...] Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit. [...] Otherwise, the unordered initialization of a variable is indeterminately sequenced with respect to every other dynamic initialization.
据我了解,您有未定义的行为,如 Quux<unsigned>::content
的初始化与 wobble
的初始化不确定地排序:
[介绍.执行]/13
Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which.
也就是说,您的程序有可能访问未动态初始化的 Quux<unsigned>::content
.
显式特化解决了问题。
请注意,在任何动态初始化之前,都会发生零初始化。因此,可以使用指针和动态内存分配来克服初始化顺序的问题:
template <typename T>
class Quux{
private:
static std::vector<T>* content;
static void create() { if(!content) content = new std::vector<T>; };
public:
static void insert(T t){ create(); content->push_back(t); }
static size_t size(){ create(); return content->size(); }
};
template <typename T>
std::vector<T>* Quux<T>::content;
这会在程序结束时引入“内存泄漏”;如果这是一个问题,您可以添加一个删除器对象,即删除 content
的另一个静态数据成员自行销毁(半个 RAII)。
关于c++ - 在 main 之前将内容插入模板类的静态容器中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17443163/