2012-01-16 14 views
19

es una pregunta bastante básica pero no entiendo por qué el código siguiente no se compila en GCC 4.6.1. Que se compila en VS 2008 con SP1:Extraño error de compilación de GCC (ejemplo simple incluido)

#include <iostream> 

class MyClass 
{ 
public: 
    const static int MinValue = -1000; 
    const static int MaxValue = 1000; 
}; 

void printValue(int i) 
{ 
    std::cout << i << std::endl; 
} 

int main(int argc, char** argv) 
{ 
    printValue(MyClass::MinValue); 
    printValue(MyClass::MaxValue); 
    printValue(argc < 42 ? MyClass::MinValue : MyClass::MaxValue); //This line gives the error 
} 

CCG dice:

[email protected]:~/temp$ g++ test.cpp 
/tmp/ccN2b95G.o: In function `main': 
test.cpp:(.text+0x54): undefined reference to `MyClass::MinValue' 
test.cpp:(.text+0x5c): undefined reference to `MyClass::MaxValue' 
collect2: ld returned 1 exit status 

Sin embargo, si saco la tercera llamada a 'printValue' entonces se construye y funciona adecuadamente. Entonces, ¿tiene algo que ver con el '?' operador ... ¿no es válido usarlo así? Además, si reemplazo el 'argc < 42' con 'verdadero' o 'falso', también se compilará bien.

¿Alguna idea ?!

+1

¿Error del compilador? –

+2

@VJovic: No, debe haber una definición si es * odr-used *, es decir "a menos que sea un objeto que cumpla los requisitos para aparecer en una expresión constante y la conversión lvalue-r-value se aplica inmediatamente" . Ese es el caso para los argumentos de la función, pero no para el resultado del operador condicional cuando la condición no es una expresión constante y el resultado es un valor l. –

+1

@MikeSeymour: Creo que he leído algunos correos acerca de odr-used y los operadores ternarios, ¿te importaría expandir esto en una respuesta correcta? Realmente me gustaría entender la sutileza aquí. –

Respuesta

7

es necesario definir sus miembros estáticos fuera de la declaración de la clase:

class MyClass 
{ 
public: 
    const static int MinValue; 
    const static int MaxValue; 
}; 


//implementation file 
const int MyClass::MinValue = -1000; 
const int MyClass::MaxValue = 1000; 
+1

no explica por qué está fallando el último 'printValue'. – greatwolf

+4

¿De verdad pensé que solo se aplicaba a tipos no integrales? O lo estoy confundiendo con otra cosa. Además, ¿por qué se compilan las primeras dos llamadas a printValue? – PolyVox

+0

@VictorT. lo hace, porque está tratando de acceder a un miembro estático que no está definido de manera válida. –

0

Voy a salir en una extremidad y decir que esto es probablemente un error del compilador con la versión que está utilizando. Como señaló AzzA en su comentario, gcc-4.5.1 parece construirlo bien al igual que gcc-4.3.4. También probé esto con CLang 2.9 y eso también acepta el código.

Como alternativa, puede definir sus valores mínimos/máximos con enumeraciones en lugar de constantes estáticas. Esto ahorrará algo de tecleo:

#include <iostream> 

class MyClass 
{ 
public: 
    enum { MinValue = -1000, MaxValue = 1000 }; 
}; 

void printValue(const int i) 
{ 
    std::cout << i << std::endl; 
} 

int main(int argc, char** argv) 
{ 
    printValue(MyClass::MinValue); 
    printValue(MyClass::MaxValue); 
    printValue(argc < 42 ? MyClass::MinValue : MyClass::MaxValue); 
} 
+0

+1 Sí, revisé GCC 4.3.4 también hace 5 minutos. Bastante interesante. – lapk

+0

Inicialmente asumí que era un error del compilador pero, dada la explicación de Mike Seymour, parece que podría ser correcto. En cambio, gcc-4.5.1 y 4.3.4 aceptan código no válido, lo que significa que hubo un error que ahora se ha solucionado. – PolyVox

+0

Como referencia, Clang 3.0 acepta el código. –

18

De acuerdo con la "Regla Una Definición", una variable debe tener exactamente una definición si es que se usa RLL-. Esto se define por la norma C++ 11:

3,2/2 Una función sobrecargado no variable o cuyo nombre aparece como una expresión evaluada potencialmente se utiliza ODR-a menos que es un objeto que satisface los requisitos para que aparece en una expresión constante y la conversión lvalue-to-rvalue se aplica inmediatamente.

y el propio ODR:

3,2/3 Cada programa deberá contener exactamente una definición de cada función o variable no está en línea que ODR-usa en ese programa; no se requiere diagnóstico.

Como argumentos llamada a la función, no son ODR-usado: son constantes con un valor especificado en su declaración, por lo que pueden aparecer en una expresión constante; y se pasan por valor, por lo que se convierten inmediatamente en valores.

Este no es el caso cuando se usan en la expresión condicional. Ya que ambos son lvalues ​​se hace referencia al mismo tipo, el resultado de la expresión condicional será un lvalue, de acuerdo con una de las reglas más bien complicados que definen el operador condicional:

5,16/4 Si el segundo y tercer operandos son glvalues ​​de la misma categoría de valor y tienen el mismo tipo, el resultado es de ese tipo y categoría de valor.

(Esta regla permite expresiones como (a?b:c)=d.)

De modo que las constantes en sí mismas no se convierten inmediatamente en valores r, y la expresión condicional no puede aparecer en una expresión constante debido a la condición de tiempo de ejecución; por lo tanto, son usados ​​y, por lo tanto, necesitan una definición.

Como observa, al cambiar la condición a una expresión constante corrige el error de enlace; también cambiaría el tipo de una constante. Pero la expresión, tal como está, requiere que tengan una definición en una (y solo una) unidad de traducción:

const int MyClass::MinValue; 
const int MyClass::MaxValue; 
+0

Gracias Mike. Por extraño que parezca, Clang 3.0 todavía acepta el código. –

+0

+1 Buena información. En una nota al margen, vaya, voy a gastar todo mi permiso '+ 1' en las respuestas a esta pregunta ... Espero que no haya otra respuesta informativa, que tendré que' '+ 1' por equidad. – lapk

+0

Puede agregar que las violaciones de la regla de una definición son "sin necesidad de diagnóstico" (un concepto que la norma no parece definir, pero que conduce inevitablemente a un comportamiento indefinido, ya que la norma "omite la descripción de cualquier definición explícita de comportamiento ") –