Как заставить статический член быть инициализированным? - PullRequest
19 голосов
/ 21 июня 2011

Рассмотрим пример кода:

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

Хотя я все еще хотел бы, чтобы производный класс не делал этого.: |

Ответы [ 4 ]

11 голосов
/ 23 июня 2011

Рассмотрим:

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;
0 голосов
/ 23 июня 2011

Как вы проверяете значение, установленное Bar. Я изменил ваш код и добавил в бар еще одну функцию:

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

и это дает мне именно ожидаемый результат. Возможно, я не правильно понимаю, чего именно вы хотите достичь?

Статические члены совместно используются объектами, поэтому их область действия должна быть разрешена при доступе. вот почему мы используем ::, явно сообщая компилятору, что это член класса, к которому мы хотим получить доступ.

0 голосов
/ 23 июня 2011

Что-то подобное приходит мне в голову:

// 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);
0 голосов
/ 21 июня 2011

Есть ли способ принудительно инициализировать пустышку (фактически вызывая register_) без какого-либо экземпляра Bar или Foo (без экземпляров, поэтому без хитрости конструктора)?

Разве этого не достаточно?

std::cout << Foo<int>::dummy;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...