考虑这个示例代码:
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_
),不用 Bar
的任何实例或Foo
(没有实例,所以没有构造函数欺骗)并且没有Foo
的用户需要以某种方式明确说明成员?额外的cookie,不需要派生类做任何事情。
修改:Found a way,对派生类的影响最小:
struct Bar
: Foo<Bar>
{ // vvvvvvvvvvvv
static char const get_dummy() { (void)dummy; return 42; }
};
尽管如此,我仍然希望派生类不必这样做。 :|
答案 0 :(得分:9)
考虑:
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;
答案 1 :(得分:1)
我们可以使用基于必须使用类实例化的声明的简单技巧:
template<…>
struct Auto {
static Foo foo;
static_assert(&foo);
};
template<…> Foo Auto::foo=…;
请注意,一些编译器警告比较为null。可以通过&foo==&foo
,(bool)&foo
或((void)&foo,true)
来避免这种情况。
还要注意,GCC 9 doesn’t count this as an odr-use。
答案 2 :(得分:0)
有没有办法强制虚拟初始化(有效地调用register_)而没有任何Bar或Foo实例(没有实例,所以没有构造函数欺骗)?
这不足够吗?
std::cout << Foo<int>::dummy;
答案 3 :(得分:0)
您如何检查Bar设置的值。 我改变了你的代码并在bar中添加了另一个函数:
....
static char const get_dummy(int){return Foo<Bar>::dummy;}
....
它给了我完全预期的结果。我可能没有正确理解,你到底想要达到什么目的?
静态成员在对象之间共享,因此必须在访问时解析其范围。这就是为什么我们使用::通过明确告诉编译器这是我们想要访问的类的成员。
答案 4 :(得分: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);