How to force a static member to be initialized?

本小妞迷上赌 提交于 2019-11-26 08:16:26

问题


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. :|


回答1:


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;



回答2:


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 doesn’t count this as an odr-use.




回答3:


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



回答4:


How are you checking the value set by Bar. I changed your code and added another function in bar as:

....
static char const get_dummy(int){return Foo<Bar>::dummy;}
....

and it is giving me exactly the expected result. I may not be understanding correctly, what do you exactly want to achieve ?

Static members are shared among the objects so their scope must be resolved at access. that is why we use :: by telling compiler explicitly that this is the member of the class we want to access.




回答5:


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;


来源:https://stackoverflow.com/questions/6420985/how-to-force-a-static-member-to-be-initialized

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!