2011-06-21 60 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);