Referencia no definida al miembro de la clase estática

¿Alguien puede explicar por qué el siguiente código no se comstackrá? Al menos en g ++ 4.2.4.

Y, lo que es más interesante, ¿por qué comstackrá cuando lanzo MEMBER a int?

#include  class Foo { public: static const int MEMBER = 1; }; int main(){ vector v; v.push_back( Foo::MEMBER ); // undefined reference to `Foo::MEMBER' v.push_back( (int) Foo::MEMBER ); // OK return 0; } 

Necesita definir realmente el miembro estático en algún lugar (después de la definición de la clase). Prueba esto:

 class Foo { /* ... */ }; const int Foo::MEMBER; int main() { /* ... */ } 

Eso debería deshacerse de la referencia indefinida.

El problema surge debido a un interesante choque de nuevas características de C ++ y a lo que estás tratando de hacer. Primero, echemos un vistazo a la firma push_back :

 void push_back(const T&) 

Espera una referencia a un objeto de tipo T Bajo el antiguo sistema de inicialización, tal miembro existe. Por ejemplo, el siguiente código comstack muy bien:

 #include  class Foo { public: static const int MEMBER; }; const int Foo::MEMBER = 1; int main(){ std::vector v; v.push_back( Foo::MEMBER ); // undefined reference to `Foo::MEMBER' v.push_back( (int) Foo::MEMBER ); // OK return 0; } 

Esto se debe a que hay un objeto real en alguna parte que tiene ese valor almacenado en él. Sin embargo, si cambia al nuevo método para especificar miembros de const estáticos, como lo ha hecho anteriormente, Foo::MEMBER ya no es un objeto. Es una constante, algo similar a:

 #define MEMBER 1 

Pero sin los dolores de cabeza de una macro de preprocesador (y con seguridad tipo). Eso significa que el vector, que está esperando una referencia, no puede obtener uno.

El estándar de C ++ requiere una definición para su miembro static const si la definición es de alguna manera necesaria.

La definición es obligatoria, por ejemplo, si se usa su dirección. push_back toma su parámetro por referencia constante, y tan estrictamente el comstackdor necesita la dirección de su miembro y necesita definirlo en el espacio de nombres.

Cuando explícitamente lanzas la constante, estás creando un temporal y es este temporal el que está vinculado a la referencia (bajo reglas especiales en el estándar).

Este es un caso realmente interesante, y de hecho creo que vale la pena plantear un problema para que el estándar se cambie y tenga el mismo comportamiento para su miembro constante.

Aunque, de una manera extraña, esto podría verse como un uso legítimo del operador unario ‘+’. Básicamente, el resultado del unary + es un valor r y, por lo tanto, se aplican las reglas para el enlace de valores a las referencias de const y no usamos la dirección de nuestro miembro de configuración estática:

 v.push_back( +Foo::MEMBER ); 

Aaa.h

 class Aaa { protected: static Aaa *defaultAaa; }; 

Aaa.cpp

 // You must define an actual variable in your program for the static members of the classes static Aaa *Aaa::defaultAaa; 

No tengo idea de por qué funciona el elenco, pero Foo :: MEMBER no está asignado hasta la primera vez que se carga Foo, y como nunca lo estás cargando, nunca se asigna. Si tuviera alguna referencia a un Foo en alguna parte, probablemente funcionaría.

En cuanto a la segunda pregunta: push_ref toma referencia como parámetro, y no puede tener una referencia a estást const memeber de una clase / struct. Una vez que llame a static_cast, se crea una variable temporal. Y se puede pasar una referencia a este objeto, todo funciona bien.

O al menos mi colega que resolvió esto dijo eso.

Con C ++ 11, lo anterior sería posible para tipos básicos como

 class Foo { public: static constexpr int MEMBER = 1; }; 

La parte constexpr crea una expresión estática en oposición a una variable estática, y se comporta como una definición de método en línea extremadamente simple. Sin embargo, el enfoque resultó un poco tambaleante con constexprs C-string dentro de las clases de plantillas.