[英]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.