2011-10-31 34 views
7

El código siguiente se compila con G ++ 4.6.1, pero no con Visual Studio 2008tiro y el operador ternario en C++

return (m_something == 0) ? 
    throw std::logic_error("Something wrong happened") : m_something; 

El hecho es que el compilador de Visual Studio realiza un accidente interno.

Quiero saber si esto es C++ estándar y por qué no se compila con Visual Studio, pero lo hace con G ++?

+8

Independientemente de este código válido estar o no de acuerdo con la norma, cuando un compilador se bloquea con un error interno del compilador (que es lo que VC hace, IIUC), entonces eso es un error en el compilador. Se supone que un compilador debe emitir un mensaje significativo incluso para el código defectuoso, no un informe de fallas. – sbi

+0

Tenga en cuenta que este es el * operador condicional *, que resulta ser * a * operador ternario. – GManNickG

+0

Sí, me confundí cuando "ternario" no estaba en la especificación en ninguna parte. –

Respuesta

11

Es estándar C++. Cualquiera (o ambas) de las expresiones then/else en una expresión condicional se permite en su lugar ser una expresión de lanzamiento (C++ 98 5.16/2).

Si Visual Studio falla al compilarlo ... ¡parece desafortunado!

+1

§5.16/2 permite que ambas expresiones sean expresiones de lanzamiento en C++ 11. – Mat

+0

@Mat: oops, tiene toda la razón, el texto aquí no ha cambiado, y la segunda alternativa permite que ambos sean lanzados en C++ 98 también. –

4

Comeau compila sin errores (aquí está mi caso mínimo prueba compilables):

int main(void) 
{ 
    int x = 17; 
    return x ? throw "Something wrong happened" : 5; 
} 

que es bastante buena evidencia de que es permitido por la norma. También lo es el hecho de que MSVC falla, en lugar de fallar limpiamente con un error.

Además, parece que se fije en VC++ 2010

R:\>cl ternarythrowtest.cpp 
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 
Copyright (C) Microsoft Corporation. All rights reserved. 

ternarythrowtest.cpp 
Microsoft (R) Incremental Linker Version 10.00.40219.01 
Copyright (C) Microsoft Corporation. All rights reserved. 

/out:ternarythrowtest.exe 
ternarythrowtest.obj 

y x64 versión:

R:\>cl ternarythrowtest.cpp 
Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64 
Copyright (C) Microsoft Corporation. All rights reserved. 

ternarythrowtest.cpp 
Microsoft (R) Incremental Linker Version 10.00.40219.01 
Copyright (C) Microsoft Corporation. All rights reserved. 

/out:ternarythrowtest.exe 
ternarythrowtest.obj 

Actualiza su compilador, si es posible, esto está lejos de ser el único error corregido en 2010.

+0

De hecho, esto es probablemente debido al cumplimiento de C++ 11, vea la respuesta de @ MooingDuck. –

+1

@ AndréCaron: Eso no explica un "Error interno del compilador". Y ver la respuesta de John, también está permitida en C++ 98. –

+0

Estoy en el equipo de @fmorency, y soy el que se encontró con el bloqueo del compilador de Microsoft con su expresión de operador ternario. Estábamos tratando de averiguar si era estándar, no si esto es un error en el compilador de Microsoft (obviamente, hay * un * error, ya que se bloquea). –

3

Desde el Proyecto de C++ 11 de febrero de

§ 5.16/2 Si el segundo o el tercer operando tiene el tipo (posiblemente cv-cualificado) vacío, entonces el valor-i-a-valor p (4.1) , las conversiones estándar de matriz a puntero (4.2) y de función a puntero (4.3) se llevan a cabo en el segundo y tercer operandos, y uno de los siguientes debe contener:
- El segundo o tercer operando (pero no ambos) es una expresión de lanzamiento (15.1); el resultado es del tipo del otro y es un valor prve.
- Tanto el segundo como el tercer operandos tienen tipo vacío; el resultado es de tipo vacío y es un valor prve. [Nota: Esto incluye el caso donde ambos operandos son expresiones de lanzamiento. nota -fin]

Parece que throw cuenta como evaluar a un void, y que esto está permitido.

+1

C++ 11 es escasamente relevante para VS2008 (excepto que esta no es una regla de C++ 11, no ha cambiado desde C++ 98, consulte la respuesta de John). –

+0

No tengo una copia del borrador de C++ 03 (para VS2008) para citar, o habría citado de eso en su lugar. Tienes razón de que no se aplica necesariamente a VS2008 sin embargo. –

1

El bloqueo interno se puede considerar un error de Visual Studio. Un compilador nunca debe bloquearse debido al código que se está compilando.

Este es un uso muy extraño del operador ternario, un simple si antes de que el regreso sería un lenguaje mucho más preferible:

if(m_something == 0) 
    throw std::logic_error("Something wrong happened"); 

return m_something; 
Cuestiones relacionadas