2011-02-12 17 views
11

Busco una especie de hacky solución al siguiente problema: GCC 4.4+ acepta el siguiente código C++ 0x:emulación "clase de enumeración" o alternativa sólida para MSVC 10,0

enum class my_enum 
{ 
    value1, 
    value2 
}; 

Qué permite el uso como este:

my_enum e = my_enum::value1; 

con todas las características que esto conlleva. Me gustaría hacer que este código sea compatible con MSVC 2010, en el sentido de que la sintaxis de uso no cambia. Ya pondere esto antes de here, y la respuesta aceptada funciona, pero la necesidad de los dos nombres diferentes para los valores enum y enum está acabando con la compatibilidad de los dos enfoques. Esto hace, por supuesto, inutilizable reemplazar el código C++ 0x tal como está. Me pregunté si algunos trucos de #undef y #define podrían solucionar esto, permitiéndome usarenum class -como la sintaxis (quizás sin el tipo de seguridad estricto, etc.), pero al menos con la misma sintaxis. ¡Gracias!

Respuesta

20

acabo de descubrir un problema con un buen corte de James (que tengo hasta ahora estado usando) y una solución al problema. Descubrí el problema cuando traté de definir un operador de ruta para my_enum.

#include <iostream> 

struct my_enum { 
    enum type { 
     value1, 
     value2 
    }; 

    my_enum(type v) : value_(v) { } 

    operator type() const { return value_; } 

private: 

    type value_; 
}; 

std::ostream& 
operator<<(std::ostream& os, my_enum v) 
{ 
    return os << "streaming my_enum"; 
} 

int main() 
{ 
    std::cout << my_enum::value1 << '\n'; 
} 

La salida es:

0 

El problema es my_enum::value1 tiene tipo diferente de my_enum. Aquí hay un truco al truco de James que se me ocurrió.

struct my_enum 
{ 
    static const my_enum value1; 
    static const my_enum value2; 

    explicit my_enum(int v) : value_(v) { } 

    // explicit // if you have it! 
     operator int() const { return value_; } 

private: 

    int value_; 
}; 

my_enum const my_enum::value1(0); 
my_enum const my_enum::value2(1); 

Notas:

  1. menos que se especifique de otra manera por un enum-base, el tipo subyacente de una enumeración de ámbito es int.
  2. Se permiten las conversiones explícitas desde y hacia el tipo integral subyacente. Pero las conversiones implícitas no lo son. Haz tu mejor esfuerzo.
  3. Este truco es más pita que James debido a la necesidad de enumerar los valores dos veces. ¡Espero que los compiladores sin soporte enum de ámbito se extingan rápidamente!
+0

Muy buena solución. –

+0

Solución increíble. Esto debería ser wikied. – FailedDev

+1

Este enfoque no parece permitir 'switch' /' case', al menos en MSVC 10 (obtengo "C2051: expresión de caso no constante"). Este es un gran PITA, ya que los 'enum's se usan normalmente de esta manera. –

5

No utilice esta solución. Vea la respuesta aceptada por Howard para una mejor solución. Dejo esta publicación aquí porque la respuesta de Howard se refiere a eso.

Si necesita compilar su código con un compilador que aún no admite una característica de idioma nueva, aún no estándar o no ampliamente implementada, es mejor evitar usar esa función de idioma en su código.

Dicho esto, como una solución corte, se puede envolver el enum en un struct y utilizar un par de conversiones implícitas:

struct my_enum { 
    enum type { 
     value1, 
     value2 
    }; 

    my_enum(type v) : value_(v) { } 

    operator type() const { return value_; } 

private: 

    type value_; 
}; 
+0

¿Es esto un patrón? ¿Por qué lo considera un hack? Está limpio. – Inverse

+1

@Inverso: si lo usa repetidamente, se convertiría en un patrón :-). Envolver una enumeración en una estructura o espacio de nombres para evitar la contaminación del espacio de nombres es una técnica común y una que uso de manera consistente (bueno, principalmente). Usar conversiones implícitas para permitir que la estructura de encapsulación se use como si fuera la enumeración no es un patrón común, al menos no en ningún código que he tenido el placer de leer. Soy cauteloso debido a las conversiones de implicación: continuamente descubro diferentes formas en que las conversiones implícitas le permiten escribir código sutilmente roto ... –

0

He estado luchando durante todo un día para encontrar una solución verdaderamente óptima, pero no parece ser una.Necesito mi enumeración que es

  1. No convertir implícitamente a un tipo entero
  2. utilizable en un comunicado switch
  3. Se puede usar como parámetro de plantilla no Tipo

En han llegado con la siguiente código, basado en la solución de Howard Hinnant:

struct DataType 
{ 
    struct integral { 
     enum type { None, Single, Double, Int }; 
    }; 

    typedef typename integral::type integral_type; 

    explicit DataType(integral_type v) : val(v) {} 
    integral_type integral_value() const { return val; } 

    bool operator==(const DataType& s) const { return val == s.val; } 
    bool operator!=(const DataType& s) const { return val != s.val; } 

    static const DataType None; 
    static const DataType Single; 
    static const DataType Double; 
    static const DataType Int; 

private: 
    integral_type val; 
}; 

En el .cpp archivo:

const DataType DataType::None (DataType::integral::None); 
const DataType DataType::Single (DataType::integral::Single); 
const DataType DataType::Double (DataType::integral::Double); 
const DataType DataType::Int (DataType::integral::Int); 

Como parámetro de plantilla no Tipo:

template <DataType::integral_type> 
struct DataTypeTraits; 

template <> 
struct DataTypeTraits<DataType::integral::Single> 
{ 
    enum { size = 4 }; 
}; 

En un interruptor:

size_t get_size(DataType type) 
{ 
    switch (type.integral_value()) { 
     case DataType::integral::Single: return DataTypeTraits<DataType::integral::Single>::size; 
     case DataType::integral::Double: return DataTypeTraits<DataType::integral::Double>::size; 
     case DataType::integral::Int:  return DataTypeTraits<DataType::integral::Int>::size; 
     default:       throw std::logic_error("Unknown data type."); 
    } 
} 

No es especialmente grande, pero eso es tan bueno como se pone, supongo. ..

Cuestiones relacionadas