2011-06-21 92 views
15

考慮這個例子的代碼:(Also on Ideone如何強制一個靜態成員被初始化?

template<class D> 
char register_(){ 
    return D::get_dummy(); // static function 
} 

template<class D> 
struct Foo{ 
    static char const dummy; 
}; 

template<class D> 
char const Foo<D>::dummy = register_<D>(); 

struct Bar 
    : Foo<Bar> 
{ 
    static char const get_dummy() { return 42; } 
}; 

我期望dummy,因爲是Foo一個具體的實例,我有Bar得到儘快初始化。 This question(和最後的標準報價)解釋得很清楚,爲什麼沒有發生。

尤其是,靜態數據成員的初始化(以及任何相關的副作用)不會發生,除非靜態數據成員本身以需要定義靜態數據成員存在。

有什麼辦法來dummy進行初始化(有效調用register_沒有BarFoo任何情況下(沒有實例,所以沒有構造欺騙)和無Foo需要用戶明確以某種方式陳述會員?額外的餅乾不需要派生類來做任何事情。


編輯Found a way對派生類的影響最小:

struct Bar 
    : Foo<Bar> 
{ //        vvvvvvvvvvvv 
    static char const get_dummy() { (void)dummy; return 42; } 
}; 

不過,我還是想在派生類沒有做到這一點。 :|

+0

我們一般不希望編譯器初始化所有類模板所有未使用的變量。在這種情況下,編譯器應該如何知道**你想要它?通過實際使用它? –

+1

@Bo:當然,但我想隱藏派生類/外部世界的用法,並且寧願以某種方式將其用於'Foo'本身。 :/ – Xeo

+0

@Xeo:'static char const get_dummy(){(void)dummy;返回42; }' - 我懷疑'Bar :: get_dummy()'和'Foo :: dummy'之間的這個循環依賴關係可以保證工作(通過標準)。看起來像高度依賴實施的技巧。我錯了嗎? –

回答

8

考慮:

template<typename T, T> struct value { }; 

template<typename T> 
struct HasStatics { 
    static int a; // we force this to be initialized 
    typedef value<int&, a> value_user; 
}; 

template<typename T> 
int HasStatics<T>::a = /* whatever side-effect you want */ 0; 

也有可能不會引入任何成員:

template<typename T, T> struct var { enum { value }; }; 
typedef char user; 

template<typename T> 
struct HasStatics { 
    static int a; // we force this to be initialized 
    static int b; // and this 

    // hope you like the syntax! 
    user :var<int&, a>::value, 
     :var<int&, b>::value; 
}; 

template<typename T> 
int HasStatics<T>::a = /* whatever side-effect you want */ 0; 

template<typename T> 
int HasStatics<T>::b = /* whatever side-effect you want */ 0; 
+0

第一個似乎工作[在海灣合作委員會](http:// ideone。com/4t1mi),但在MSVC10中並不好,不會進行初始化。 :/第二個適用於[無GCC](http://ideone.com/s85LF)和MSVC10。 :(**編輯**:哦,等待,啓用C++ 0x [它在GCC上工作](http://ideone.com/s85LF)。仍然沒有MSVC的運氣... – Xeo

+0

@Xeo它適用於我沒有C++ 0x在gcc4.6上沒有任何其他編譯器可以嘗試,除了clang,在clang中第二個也不起作用,PR正在開發中。 –

+1

哦,天哪!什麼'user:var :: value'的意思是? –

0

有沒有什麼辦法強制啞元初始化(有效調用register_)沒有任何Bar或Foo的實例(沒有實例,所以沒有構造函數欺騙)?

這不就夠了嗎?

+0

我希望除了讓用戶明確聲明成員之外,還有其他方法。 :| – Xeo

+5

你問「任何方式」:) – StackedCrooked

+0

是的,澄清。 ;) – Xeo

0

您如何檢查Bar設置的值? 我改變你的代碼,並在酒吧增加了一個功能:

.... 
static char const get_dummy(int){return Foo<Bar>::dummy;} 
.... 

,它是給我完全預期的結果。我可能沒有正確理解,你究竟想要達到什麼目標?

靜態成員在對象之間共享,因此它們的作用域必須在訪問時解析。這就是爲什麼我們使用::通過明確告訴編譯器這是我們想要訪問的類的成員。

0

類似的東西在我腦海中:

// in some c++ file (to make i with internal linkage) 
static int i = init_dummy(Foo<int>::dummy); 

其中init_dummy這樣定義:

int init_dummy(...) 
{ 
    return 1; 
} 

由於變量ARGS你可以把更多的初始化有這樣的:

static int i = init_dummy(Foo<int>::dummy, Foo<double>::dummy, Foo<whatever>::dummy);