如何强制静态成员初始化?

Xeo*_*Xeo 20 c++ templates static-members static-initialization

考虑这个示例代码:

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; }
};
Run Code Online (Sandbox Code Playgroud)

(也在Ideone上.)

我期望dummy得到尽快初始化为有一个具体的实例Foo,我有Bar.这个问题(以及最后的标准引用)解释得很清楚,为什么没有发生.

[...]特别是,除非静态数据成员本身以需要静态数据成员的定义存在的方式使用,否则不会发生静态数据成员的初始化(以及任何相关的副作用).

有没有办法强制 dummy初始化(有效调用register_)没有任何实例BarFoo(没有实例,所以没有构造函数欺骗),没有用户Foo需要以某种方式明确说明成员?额外的cookie,不需要派生类做任何事情.


编辑:找到一种方法,对派生类的影响最小:

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

虽然,我仍然喜欢派生类不必这样做.:|

Joh*_*itb 11

考虑:

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;
Run Code Online (Sandbox Code Playgroud)

在没有引入任何成员的情况下也可以:

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;
Run Code Online (Sandbox Code Playgroud)

  • @pure:这是一个未命名的位域,实际上是一个`char:0;` (3认同)
  • 哦,天哪!什么`user:var <int&,a> :: value`的意思? (2认同)

Dav*_*ing 5

我们可以使用一个基于必须用类实例化的声明的简单技巧:

\n\n
template<\xe2\x80\xa6>\nstruct Auto {\n  static Foo foo;\n  static_assert(&foo);\n};\ntemplate<\xe2\x80\xa6> Foo Auto::foo=\xe2\x80\xa6;\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,某些编译器会警告与 null 的比较;&foo==&foo如果需要,可以使用、(bool)&foo或 来避免((void)&foo,true)

\n\n

另请注意,GCC 9.0\xe2\x80\x939.2 don\xe2\x80\x99t 将此视为 odr-use

\n