c++ - ¿Cómo forzar a un miembro estático a inicializarse?
c++ class static member (4)
Considere este código de ejemplo:
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; }
};
( También en Ideone .)
Esperaría que el dummy
se inicializara tan pronto como haya una instanciación concreta de Foo
, que tengo con Bar
. Esta pregunta (y la cita estándar al final) explica bastante claro, por qué eso no está sucediendo.
[...] en particular, la inicialización (y cualquier efecto secundario asociado) de un miembro de datos estáticos no se produce a menos que el miembro de datos estáticos se use de una manera que requiera la definición del miembro de datos estáticos.
¿Hay alguna forma de forzar que el dummy
se inicialice (llamando efectivamente register_
) sin ninguna instancia de Bar
o Foo
(sin instancias, por lo que no hay trucos de constructor) y sin que el usuario de Foo
tenga que indicar explícitamente al miembro de alguna manera? Cookies adicionales por no necesitar la clase derivada para hacer cualquier cosa.
Editar : Encontré una manera con un impacto mínimo en la clase derivada:
struct Bar
: Foo<Bar>
{ // vvvvvvvvvvvv
static char const get_dummy() { (void)dummy; return 42; }
};
Sin embargo, me gustaría que la clase derivada no tenga que hacer eso. : |
¿Hay alguna forma de obligar al dummy a inicializarse (llamando efectivamente register_) sin ninguna instancia de Bar o Foo (sin instancias, entonces no hay trucos de constructor)?
¿No sería esto suficiente?
std::cout << Foo<int>::dummy;
¿Cómo estás controlando el valor establecido por Bar? Cambié tu código y agregué otra función en la barra como:
....
static char const get_dummy(int){return Foo<Bar>::dummy;}
....
y me está dando exactamente el resultado esperado. Puede que no esté entendiendo correctamente, ¿qué es exactamente lo que quieres lograr?
Los miembros estáticos se comparten entre los objetos, por lo que su alcance se debe resolver en el momento del acceso. es por eso que usamos :: al decirle al compilador explícitamente que este es el miembro de la clase a la que queremos acceder.
Algo así viene a mi mente:
// in some c++ file (to make i with internal linkage)
static int i = init_dummy(Foo<int>::dummy);
donde init_dummy se define así:
int init_dummy(...)
{
return 1;
}
Debido a argumentos variables, puede poner más inicializaciones allí, como:
static int i = init_dummy(Foo<int>::dummy, Foo<double>::dummy, Foo<whatever>::dummy);
Considerar:
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;
También es posible sin introducir ningún miembro:
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;