2013-07-03 28 views
2

我想要建立一個只有靜態數據成員和函數的模板類,基本上是一些函數的集合,我想要填充代碼的各個部分。我試圖在到達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通過結構Bar就好運行main()之前插入的東西。我希望這是一貫的行爲,而不是我幸運?

但是,當我嘗試爲模板類Quux<T>做同樣的事情時,似乎我必須等到main()才能添加內容。有人可以解釋爲什麼這是必要的(希望)解決方法?我認爲它與模板實例化的時間有關,但我無法弄清楚爲什麼。我希望Quux<unsigned>是完全可用後執行以下操作:

struct Wobble{ 
    Wobble(){ Quux<unsigned>::insert(0); } 
} wobble; 

缺少什麼我在這裏?爲什麼我可以在main之前通過bar將內容添加到非模板類中,但是我不能通過wobble做同樣的事情嗎?有沒有什麼方法可以獲得與模板類中的FooBar相同的行爲?

+0

如果從'Quux <> :: content'中刪除初始值設定項,會發生什麼?矢量將始終初始化爲空。 – arne

+0

@arne萬事大吉! '/tmp/cc9EjNZp.o:函數'Quux :: insert(unsigned int)': sscce.cpp :(.text._ZN4QuuxIjE6insertEj [Quux :: insert(unsigned int)] +在函數'Quux :: size()'中: sscce.cpp :(.text._ZN4QuuxIjE4sizeEv [ Quux :: size()] + 0x5):未定義引用Quux :: content' collect2:ld返回1退出狀態 ' –

+0

如果添加'Quux '的明確實例' *在'class Wobble'的定義之前,它按預期工作。 – dyp

回答

3

[basic.start.init]/2

顯式專用類模板的定義靜態數據成員已經命令初始化。其他類模板靜態數據成員(即,隱式或顯式實例化的特化)具有無序初始化。 [...]在單個翻譯單元中定義的有序初始化變量應在翻譯單元中以其定義的順序 進行初始化。 [...]否則,就每個其他動態初始化而言,變量的無序初始化都是不確定的。

據我瞭解,你具有不確定的行爲,爲Quux<unsigned>::content的初始化不定與wobble初始化序列:

[簡介。執行]/13

評價A和B時是A B或B A之前進行測序之前進行測序的測序不定,但它是未指定的哪個。

也就是說,您的程序可能會訪問一個未動態初始化的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)。

+0

+1爲相關標準報價。 – arne

+0

非常感謝您的回答,特別是標準報價。我現在知道了!我將使用動態分配和刪除對象,這對我來說似乎很優雅。 –

1

你應該確定的第一次擺動之前增加對未簽名的內容載體的顯式實例,即

template<> 
std::vector<unsigned> Quux<unsigned>::content=std::vector<unsigned>(); 

然後它按預期工作,輸出1,1,2。

+0

感謝您的回答。這確實解決了這個問題。 –