C ++ emitiendo un valor de punto flotante a una enumeración, pero no con VS 2010

Tengo un código de plantilla que funciona bien con Xcode 4.5 y LLVM 3.0, pero falla con la cadena de herramientas VS 2010 Express C ++ (v 10.0.30319.1).

Estoy usando una API de terceros sobre la que no tengo control. Proporciona valores a mi código como “burbujas” de caja negra que solo pueden ser interpretadas por las funciones de la API:

// API_Secret is a black-box encapsulation of a floating-point number or a boolean value. // It is provided by a third-party API, with associated access functions. // For all intents and purposes, it's a complete black box. // This enum represents the internal 'type' of a secret value. enum API_SecretTypeEnum { API_Number, API_Boolean, }; // Other API declarations: API_SecretTypeEnum API_GetType(const API_Secret &value); double API_AsNumber(const API_Secret &value); bool API_AsBoolean(const API_Secret &value); // my code: template  class Extractor { public: ValueType extract(API_Secret value) { if (API_GetType(value) == API_Number) { return static_cast(API_AsNumber(value)); } else if (API_GetType(value) == API_Boolean) { return API_AsBoolean(value) ? ValueType(1) : ValueType(0); } return ValueType(); } }; // boolean specialization - not 100% sure it's needed though template class Extractor  { public: bool extract(API_Secret value) { return API_AsBoolean(value); } }; 

Entonces despúes:

 API_Secret API_GetSomeValue(int some_sort_of_handle); // get some black-box values from the API API_Secret secret0 = API_GetSomeValue(0); API_Secret secret1 = API_GetSomeValue(1); API_Secret secret2 = API_GetSomeValue(2); // for certain external reasons we expect this to be an integer representation: Extractor e0; int v0 = e0.extract(secret0); // for certain external reasons we expect this to be a double representation: Extractor e1; double v1 = e1.extract(secret1); // for certain external reasons we expect this to be a boolean representation: Extractor e2; bool v2 = e2.extract(secret2); 

Ahora, para la diferencia entre Xcode, LLVM y VS 2010. En Xcode y LLVM, se comstackrá lo siguiente (como parte del progtwig completo):

 enum MyEnum { Enum0, Enum1, }; Extractor ee; MyEnum ve = ee.extract(secret0); 

Es decir, la plantilla de clase utiliza un static_cast para convertir de un número de punto flotante a una enumeración . Esto parece funcionar bien, y la sección de explicación de esta página sugiere que esto es válido:

8) El tipo de entero, punto flotante o enumeración se puede convertir a cualquier tipo de enumeración (el resultado no se especifica si el valor de expresión, convertido al tipo subyacente de la enumeración, no es uno de los valores de enumeración de destino)

Sin embargo, con VS2010, se encuentra el siguiente error de comstackción:

error C2440: ‘static_cast’: no ​​se puede convertir de ‘double’ a ‘MyEnum’

  Conversions between enumeration and floating point values are no longer allowed 

Y este artículo de MSDN parece confirmar esto al no mencionar los tipos de punto flotante y al declarar explícitamente el valor “integral”:

El operador static_cast puede convertir explícitamente un valor integral a un tipo de enumeración. Si el valor del tipo integral no se encuentra dentro del rango de valores de enumeración, el valor de enumeración resultante no está definido.

Así que parece que hay una diferencia significativa entre VS 2010 y los otros comstackdores. Me pregunto si esto es algo que se puede evitar en VS 2010. ¿Es una característica más nueva del lenguaje que VS 2010 simplemente no admite? Sin embargo, pregunto esto porque el mensaje de error dice “ya no está permitido”, lo que implica que está explícitamente rechazado.

Conozco una solución alternativa: en lugar de utilizar una enumeración (con Extractor ), puedo usar un Extractor , y luego simplemente asignarlo a la variable MyEnum de destino. Sin embargo, esta plantilla se usa realmente como parte de un sistema más grande que llama a funciones envueltas, y en este caso la función envuelta toma un valor MyEnum. Esto evita que la plantilla coincida correctamente ya que el parámetro ValueType en realidad se toma automáticamente de la firma de la función envuelta.

Alternativamente, ¿es posible escribir una especialización de plantilla de Extractor que coincida solo con los tipos de enum ? Entonces puedo lanzar a un tipo integral primero. O tal vez la plantilla base siempre se puede convertir a un int primero, luego podría escribir una especialización de punto flotante que no haga esto, pero no estoy seguro de cómo escribir una plantilla que capture todos los tipos de punto flotante (flotante, doble, …).

Estoy bastante seguro de que Visual Studio-2010 admite . Puede usar std::enable_if junto con std::is_enum .

 template  class Extractor { public: ValueType extract(API_Secret value); }; template  class Extractor::value>::type> { ... }; 

Puede hacer lo mismo para hacer coincidir los tipos de punto flotante usando std::is_floating_point .