2012-02-26 10 views
20

Estoy usando una enumeración de ámbito para enumerar estados en alguna máquina de estados que estoy implementando. Por ejemplo, digamos que algo como:¿Equivalente a "usar el espacio de nombres X" para las enumeraciones de ámbito?

enum class CatState 
{ 
    sleeping, 
    napping, 
    resting 
}; 

En mi cpp donde defino una tabla de transición de estado, me gustaría usar algo equivalente a using namespace X de modo que yo no necesito delante de todos mis nombres de los estados con CatState::. En otras palabras, me gustaría usar sleeping en lugar de CatState::sleeping. Mi tabla de transición tiene bastantes columnas, por lo que evitar el prefijo CatState:: mantendría las cosas más compactas y legibles.

Entonces, ¿hay alguna forma de evitar tener que escribir CatState:: todo el tiempo?


Sí, sí, ya estoy enterado de las trampas de using namespace. Si hay un equivalente para enumeraciones fuertemente tipadas, prometo usarlo solo dentro de un alcance limitado en mi archivo de implementación de cpp, y no para mal.

+0

¿Realmente necesitas una 'enum class', o harías un' enum'? – netcoder

+0

Originalmente era un 'enum' simple, pero estoy haciendo la transición de mi código para usar las características de C++ 11. Me gusta la idea de seguridad de tipo más fuerte con 'enum class'. –

Respuesta

11

Entonces, ¿hay alguna manera de evitar tener que escribir CatState:: todo el tiempo?

No. Así como no hay un equivalente para tener que escribir ClassName:: para miembros de clases estáticas. No puede decir using typename ClassName y luego llegar a las partes internas. Lo mismo vale para las enum s fuertemente tipadas.

Por supuesto, no puede utilizar la sintaxis enum class, simplemente usando enum s regulares. Pero luego pierdes tipeo fuerte.

Debe tenerse en cuenta que una de las razones para usar ALL_CAPS para enumeraciones débilmente tipadas fue evitar conflictos de nombres. Una vez que tenemos un alcance completo y una tipificación fuerte, el nombre de una enumeración se identifica de manera única y no puede entrar en conflicto con otros nombres. Ser capaz de llevar esos nombres al ámbito del espacio de nombres reintroduciría este problema. Por lo tanto, es probable que desee volver a utilizar ALL_CAPS para ayudar a eliminar la ambigüedad de los nombres.

+1

+1 Gracias. Imaginaba que la enumeración fuerte era algo así como un espacio de nombres, pero pensar en ello como una (algo) clase tiene más sentido ahora. –

8

Usted podría considerar el uso de un typedef para acortar los nombres cualificados:

typedef CatState C; 

O, si las columnas son repetitivos de manera que se pueden generar con facilidad, es posible considerar el uso de una macro para generar cada fila en la tabla, lo que puede conducir a un código muy conciso (y más fácil de leer).

+0

Entonces, ¿está diciendo que no hay un equivalente de 'using namespace' para las enumeraciones? Si ese es el caso, entonces un typedef corto parece ser la mejor solución para mí. –

+0

No es que yo sepa, no. Puede usar una declaración de uso para cada enumerador (por ejemplo, 'usando CatState :: sleeping;', etc.), pero no estoy 100% seguro. Sin embargo, si el código es altamente repetitivo, recomiendo encarecidamente una macro. –

+0

+1 Terminé usando su sugerencia typedef, pero Nicol dio la respuesta directa a mi pregunta. Desearía poder aceptar ambas respuestas. –

2

La respuesta de Nicol es correcta: el lenguaje está diseñado para que usted siempre reúna los requisitos del ámbito (excepto en el alcance enum { } mismo).

Sin embargo, here is a technique se me ocurrió para los enumeradores de "ámbito" que no están abarcados dentro de las clases elegidas. Técnicamente, los enumeradores no están agrupados, por lo que aún se convertirán implícitamente en int. (No "fuertemente tipado" como lo dice). Sin embargo, en el idioma se accede utilizando el operador de ámbito después de un verdadero nombre enum, por lo que sintácticamente no hay diferencia, y por lo tanto requiere C++ 11.

#define IMPORTABLE_ENUM(TYPENAME, ...) \ 
\ 
struct import_ ## TYPENAME { \ 
    enum TYPENAME { \ 
     __VA_ARGS__ \ 
    }; \ 
}; \ 
\ 
typedef import_ ## TYPENAME :: TYPENAME TYPENAME; 

// usage: 
IMPORTABLE_ENUM (duck, huey, dewey, louie) 

duck d = duck::dewey; // can't use unscoped enumerators here 

struct duck_madness : private import_duck { // but inside a derived class 
    duck who_did_it() { return huey; } // qualification is unnecessary 
}; 
2

También me gustaría tener esta posibilidad y la limitación me resulta bastante molesta.Por lo general, es mejor que el programador decida qué funciones quiere usar. Ya sea el alcance explícito o la forma más conveniente. Si restringe al programador, abandonará toda la función por conveniencia o inventará soluciones temporales desagradables, como la siguiente plantilla segura basada en plantilla. Tendrá algunos gastos generales cuando se compile sin optimización.

template<class _Enum> 
class type_safe_enum 
{ 
private: 
    _Enum m_EnumValue; 
    operator int(); 
public: 
    inline operator _Enum() const { return m_EnumValue; } 
    inline void operator =(_Enum x) { m_EnumValue = x; } 
}; 

enum _MY_ENUM 
{ 
    Value1, 
    Value2 
}; 

enum _MY_ENUM2 
{ 
    Value3, 
    Value4 
}; 

typedef type_safe_enum<_MY_ENUM> MY_ENUM; 

void TestMyEnum() 
{ 
    MY_ENUM myEnum; 
    int x; 

    myEnum = Value1; // ok 
    // myEnum = Value3; // compilation error 
    // myEnum = 0; // compilation error 
    // x = myEnum; // compilation error 

} 
+1

Su '_Enum' y otros identificadores' _ [A-Z] + 'conducen a un comportamiento indefinido, consulte [reglas sobre caracteres de subrayado] (http://stackoverflow.com/a/228797/673852). A saber, 'Todos los identificadores que comienzan con un guión bajo y una letra mayúscula u otro guión bajo siempre están reservados para cualquier uso. 'Si el programa declara o define un identificador en un contexto en el que está reservado <...>, el comportamiento no está definido. – Ruslan

+0

Supongo que no eres del mundo de Windows, de lo contrario sabrías que MS viola ese estándar con la mayoría de sus etiquetas struct. No dije, use este código ya que es para su proyecto personal. Estos identificadores están reservados para que los programadores * normales * tengan reglas que puedan seguir y no entren en conflicto con los desarrolladores del sistema. Están reservados para desarrolladores de sistemas y idiotas locos como yo, que hacen sus propias cosas. Escribo encabezados de sistema, gestores de arranque y núcleos de sistema operativo, por lo que estas reglas no son para mí. Lo que es peor que violar esta regla es usar funciones C estándar como strcpy o asctime. – Timo

Cuestiones relacionadas