Tengo entendido que C ++ permite que los miembros constantes estáticos se definan dentro de una clase siempre que sea un tipo entero.
Entonces, ¿por qué el siguiente código me da un error de vinculador?
#include <algorithm>
#include <iostream>
class test
{
public:
static const int N = 10;
};
int main()
{
std::cout << test::N << "\n";
std::min(9, test::N);
}
El error que obtengo es:
test.cpp:(.text+0x130): undefined reference to `test::N'
collect2: ld returned 1 exit status
Curiosamente, si comento la llamada a std :: min, el código se compila y enlaza bien (aunque también se hace referencia a test :: N en la línea anterior).
¿Alguna idea de lo que está pasando?
Mi compilador es gcc 4.4 en Linux.
c++
static
declaration
definition
HighCommander4
fuente
fuente
char
, puede definirlo comoconstexpr static const char &N = "n"[0];
. Tenga en cuenta el&
. Supongo que esto funciona porque las cadenas literales se definen automáticamente. Sin embargo, estoy un poco preocupado por esto: podría comportarse de manera extraña en un archivo de encabezado entre diferentes unidades de traducción, ya que la cadena probablemente estará en varias direcciones diferentes.inline const int N = 10
, que hasta donde yo sé todavía tiene un almacenamiento en algún lugar definido por el enlazador. En este caso, también se podría usar la palabra clave en línea para proporcionar una definición de variable estática dentro de la prueba de definición de clase.Respuestas:
Tengo entendido que C ++ permite que los miembros constantes estáticos se definan dentro de una clase siempre que sea un tipo entero.
Tienes razón. Se le permite inicializar integrales constantes estáticas en la declaración de clase, pero esa no es una definición.
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr038.htm
Curiosamente, si comento la llamada a std :: min, el código se compila y enlaza bien (aunque también se hace referencia a test :: N en la línea anterior).
¿Alguna idea de lo que está pasando?
std :: min toma sus parámetros por referencia constante. Si los tomara por valor, no tendría este problema, pero como necesita una referencia, también necesita una definición.
Aquí está el capítulo / verso:
9.4.2 / 4 - Si un
static
miembro de datos es de tipoconst
integral oconst
enumeración, su declaración en la definición de clase puede especificar un inicializador constante que será una expresión constante integral (5.19). En ese caso, el miembro puede aparecer en expresiones constantes integrales. El miembro seguirá estando definido en un ámbito de espacio de nombres si se utiliza en el programa y la definición del ámbito de espacio de nombres no deberá contener un inicializador .Vea la respuesta de Chu para una posible solución.
fuente
5
a unconst int&
. Entonces, ¿por qué no tratar los OPtest::N
como el literal correspondiente?El ejemplo de Bjarne Stroustrup en sus preguntas frecuentes de C ++ sugiere que está en lo correcto, y solo necesita una definición si toma la dirección.
Dice "Puede tomar la dirección de un miembro estático si (y solo si) tiene una definición fuera de clase" . Lo que sugiere que funcionaría de otra manera. Tal vez su función min invoca direcciones de alguna manera detrás de escena.
fuente
std::min
toma sus parámetros por referencia, por lo que se requiere una definición.template<class K, class V, class C> const typename AE<K,V,C>::KeyContainer::size_type AE<K,V,C>::c7;
donde KeyContainer es un typedef de std :: vector <K>. Uno debe listar todos los parámetros de la plantilla y escribir typename porque es un tipo dependiente. Quizás alguien encuentre útil este comentario. Sin embargo, ahora me pregunto cómo exportar esto en una DLL porque la clase de plantilla está, por supuesto, en un encabezado. ¿Necesito exportar c7 ???Otra forma de hacer esto, para los tipos enteros de todos modos, es definir constantes como enumeraciones en la clase:
fuente
No solo int. Pero no puede definir el valor en la declaración de clase. Si usted tiene:
en el archivo .h, entonces debe tener:
en el archivo .cpp.
fuente
static const
miembro integral en la definición de clase. Pero eso todavía no define a ese miembro. Vea la respuesta de Noah Roberts para más detalles.Aquí hay otra forma de solucionar el problema:
(Creo que la respuesta de Crazy Eddie describe correctamente por qué existe el problema).
fuente
std::min(9, +test::N);
A partir de C ++ 11 puede utilizar:
static constexpr int N = 10;
En teoría, esto todavía requiere que defina la constante en un archivo .cpp, pero mientras no tome la dirección
N
es muy poco probable que la implementación del compilador produzca un error;).fuente
No, 3.1 §2 dice:
fuente