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

发布于 2024-11-16 12:41:35 字数 1292 浏览 4 评论 0原文

考虑这个示例代码:(

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_没有任何实例BarFoo (没有实例,因此没有构造函数欺骗)并且 Foo 的用户不需要以某种方式显式声明成员?不需要派生类做任何事情的额外cookie。


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

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

不过,我会仍然喜欢派生类不必这样做。 :|

Consider this example code:

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; }
};

(Also on Ideone.)

I'd expect dummy to get initialized as soon as there is a concrete instantiation of Foo, which I have with Bar. This question (and the standard quote at the end) explained pretty clear, why that's not happening.

[...] in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.

Is there any way to force dummy to be initialized (effectively calling register_) without any instance of Bar or Foo (no instances, so no constructor trickery) and without the user of Foo needing to explicitly state the member in some way? Extra cookies for not needing the derived class to do anything.


Edit: Found a way with minimal impact on the derived class:

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

Though, I'd still like the derived class not having to do that. :|

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

木有鱼丸 2024-11-23 12:41:35

考虑一下:

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;

Consider:

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;

It's also possible without introducing any member:

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;
愁以何悠 2024-11-23 12:41:35

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

template<…>
struct Auto {
  static Foo foo;
  static_assert(&foo);
};
template<…> Foo Auto::foo=…;

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

另请注意,GCC 9.0–9.2 不将此视为 odr-use< /a>.

We can use a simple trick based on a declaration that must be instantiated with the class:

template<…>
struct Auto {
  static Foo foo;
  static_assert(&foo);
};
template<…> Foo Auto::foo=…;

Note that some compilers warn about the comparison to null; that can be avoided with &foo==&foo, (bool)&foo, or ((void)&foo,true) if needed.

Note also that GCC 9.0–9.2 don’t count this as an odr-use.

不必了 2024-11-23 12:41:35

我想到了类似的事情:

// 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);

Something like that comes to my mind:

// in some c++ file (to make i with internal linkage)
static int i = init_dummy(Foo<int>::dummy);

where init_dummy is defined like this:

int init_dummy(...)
{
  return 1;
}

Due to variable args you can put more initializations there like:

static int i = init_dummy(Foo<int>::dummy, Foo<double>::dummy, Foo<whatever>::dummy);
允世 2024-11-23 12:41:35

我最近遇到了这个。官方解决方案是显式模板实例化,此处进行了描述。

在上述情况下,语句应如下所示:

template class Foo::Bar;

I recently bumped into this. The official solution would be explicit template instantiation, described here.

In the above case, the statement should look like this:

template class Foo::Bar;
夜无邪 2024-11-23 12:41:35

有没有办法在没有任何 Bar 或 Foo 实例的情况下强制初始化虚拟对象(有效地调用 register_)(没有实例,因此没有构造函数欺骗)?

这还不够吗?

std::cout << Foo<int>::dummy;

Is there any way to force dummy to be initialized (effectively calling register_) without any instance of Bar or Foo (no instances, so no constructor trickery)?

Wouldn't this be sufficient?

std::cout << Foo<int>::dummy;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文