2012-07-06 18 views
6

Tomemos una construcción de código que he encontrado recientemente en alguna parte en el proyecto:Enum valor de colisión con el nombre de enumeración

namespace Test 
{ 
    enum EName 
    { 
     CoolEnum, 
     NiceEnum 
    }; 

    enum CoolEnum 
    { 
     CoolVal1, 
     CoolVal2 
    }; 

    enum NiceEnum 
    { 
     NiceVal1, 
     NiceVal2 
    }; 
} 

Mi pregunta es por qué el compilador permite que algo como esto. Tomemos un ejemplo de código aquí:

Test::CoolEnum cEnum = Test::NiceVal1; // INVALID, as compiler refers to Test::CoolEnum value of Test::Ename enum 

¿Por qué se permite tal confusión? Entiendo por qué tengo que anteponer la palabra clave enum, por lo que el compilador sabe claramente que estoy declarando una variable de enumeración dada, sin usar el valor de otra enumeración en el mismo espacio de nombres. Simplemente no entiendo por qué, en primer lugar, incluso es posible hacer tal construcción.

+0

Creo que es un compilador definido porque ese código en Ideone causa errores: http://ideone.com/4GDTF – tinman

+0

Es por eso que he colocado gcc, pero hasta donde yo sé vc también permite tal construcción –

+0

@Kamil es posible que desee para cambiar los nombres de las constantes enum de NiceEnum, ya que lo copió y pegó desde CoolEnum y entran en conflicto. –

Respuesta

7

C++ de 11 clases de enumeración son la solución para esto:

namespace Test 
{ 
    enum class EName 
    { 
     CoolEnum, 
     NiceEnum 
    }; 

    enum class CoolEnum 
    { 
     NiceVal1, 
     NiceVal2 
    }; 

    enum class NiceEnum 
    { 
     NiceVal1, 
     NiceVal2 
    }; 
} 

continuación, puede utilizar el apropiado NiceVal1:

Test::CoolEnum cEnum = Test::CoolEnum::NiceVal1; 

enumeraciones Plain fueron heredadas de C, donde no existe la noción de lo que es un espacio de nombres Si las enumeraciones simples introducen algún tipo de espacio de nombres, el código C que utiliza enumeraciones no se compilará en absoluto. Es por eso que se introdujeron las clases enum, para no romper la compatibilidad con versiones anteriores.

+1

Es bueno saberlo, pero no es una respuesta a una pregunta determinada. Estoy contento de que en C++ 11 aclararon las cosas, pero me pregunto por qué en primer lugar fue posible –

+0

He colocado la misma construcción fuera del espacio de nombres y aún así es perfectamente válido para C++ –

+0

No lo hago Entiendo a qué se refiere, ¿podría ampliar o dar un ejemplo? – mfontanini

1

La respuesta es porque el estándar dicta este comportamiento. Ver 3.3.7/2:

un nombre de clase (9.1) o el nombre de la enumeración (7.2) se pueden ocultar por el nombre de un objeto, función o empadronador declarado en el mismo ámbito. Si una clase o nombre de enumeración y un objeto, función o enumerador son declarados en el mismo ámbito (en cualquier orden) con el mismo nombre, la clase nombre o enumeración está oculta donde sea que el objeto, función nombre del enumerador es visible.

Se supone que esto es para facilitar la compatibilidad con el mecanismo de C (donde un enumerador no abre un nuevo ámbito) que se ha establecido durante mucho tiempo.

En su caso, al menos con g ++ puede usar typename para indicar que desea utilizar el tipo en lugar del enumerador (typename Test::CoolEnum cEnum = Test::NiceVal1;).

En general, sin embargo, me gusta abarcar todas las enumeraciones en un espacio de nombres o clase para evitar estas colisiones por completo.

+1

"typename Test :: CoolEnum" es incorrecto: GCC acepta eso [pero debe rechazarlo] (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48920). Use "enum Test :: CoolEnum" en su lugar. –

Cuestiones relacionadas