[英]How to force a static member to be initialized?
考慮這個示例代碼:
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; }
};
(也在 Ideone 上。)
我希望dummy
只要有Foo
的具體實例化就會被初始化,我有Bar
。 這個問題(以及最后的標准報價)解釋得很清楚,為什么沒有發生。
[...] 特別是,靜態數據成員的初始化(以及任何相關的副作用)不會發生,除非靜態數據成員本身的使用方式要求靜態數據成員的定義存在。
有沒有辦法強制dummy
被初始化(有效地調用register_
)沒有任何Bar
或Foo
實例(沒有實例,所以沒有構造函數詭計)並且Foo
的用戶不需要以某種方式顯式聲明成員? 不需要派生類做任何事情的額外 cookie。
編輯:找到一種對派生類影響最小的方法:
struct Bar
: Foo<Bar>
{ // vvvvvvvvvvvv
static char const get_dummy() { (void)dummy; return 42; }
};
不過,我仍然希望派生類不必這樣做。 :|
考慮:
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;
我們可以使用一個基於必須用類實例化的聲明的簡單技巧:
template<…>
struct Auto {
static Foo foo;
static_assert(&foo);
};
template<…> Foo Auto::foo=…;
請注意,某些編譯器會警告與 null 的比較; 如果需要,可以使用&foo==&foo
、 (bool)&foo
或((void)&foo,true)
避免。
另請注意,GCC 9.0–9.2不將此視為 odr-use 。
我想到了這樣的事情:
// 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;
}
由於可變參數,您可以在其中放置更多初始化,例如:
static int i = init_dummy(Foo<int>::dummy, Foo<double>::dummy, Foo<whatever>::dummy);
您如何檢查 Bar 設置的值。 我更改了您的代碼並在 bar 中添加了另一個功能:
....
static char const get_dummy(int){return Foo<Bar>::dummy;}
....
它給了我完全預期的結果。 我可能沒有正確理解,你到底想達到什么目的?
靜態成員在對象之間共享,因此必須在訪問時解析它們的范圍。 這就是為什么我們通過明確告訴編譯器這是我們要訪問的類的成員來使用 :: 的原因。
有沒有辦法在沒有任何 Bar 或 Foo 實例(沒有實例,所以沒有構造函數技巧)的情況下強制初始化(有效地調用 register_)?
這還不夠嗎?
std::cout << Foo<int>::dummy;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.