简体   繁体   English

C ++将浮点值转换为枚举 - 但不是VS 2010

[英]C++ casting a floating point value to an enum - but not with VS 2010

I have some template code that works fine with Xcode 4.5 and LLVM 3.0, but fails with the VS 2010 Express C++ toolchain (v 10.0.30319.1). 我有一些适用于Xcode 4.5和LLVM 3.0的模板代码,但是使用VS 2010 Express C ++工具链(v 10.0.30319.1)失败了。

I'm using a third-party API that I have no control over. 我正在使用我无法控制的第三方API。 It provides values to my code as black-box 'blobs' that can only be interpreted by API functions: 它为我的代码提供的值为黑盒'blob',只能由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 <typename ValueType>
class Extractor {
 public:
  ValueType extract(API_Secret value) {
    if (API_GetType(value) == API_Number) {
      return static_cast<ValueType>(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 <bool> {
 public:
  bool extract(API_Secret value) {
    return API_AsBoolean(value);
  }
};

Then, later: 然后,后来:

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<int> e0;
int v0 = e0.extract(secret0);

// for certain external reasons we expect this to be a double representation:
Extractor<double> e1;
double v1 = e1.extract(secret1);

// for certain external reasons we expect this to be a boolean representation:
Extractor<bool> e2;
bool v2 = e2.extract(secret2);

Now for the difference between Xcode, LLVM and VS 2010. In Xcode & LLVM, the following will compile (as part of the full program): 现在了解Xcode,LLVM和VS 2010之间的区别。在Xcode和LLVM中,以下内容将编译(作为完整程序的一部分):

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

Ie the class template uses a static_cast to convert from a floating point number to an enum . 即类模板使用static_cast 从浮点数转换为枚举 This seems to work fine, and the explanation section of this page suggests this is valid: 这似乎工作正常, 本页的解释部分表明这是有效的:

8) Integer, floating-point , or enumeration type can be converted to any enumeration type (the result is unspecified if the value of expression, converted to the enumeration's underlying type, is not one of the target enumeration values) 8)可以将整数, 浮点或枚举类型转换为任何枚举类型(如果转换为枚举的基础类型的表达式的值不是目标枚举值之一,则结果未指定)

However with VS2010, the following compiler error is encountered: 但是对于VS2010,遇到以下编译器错误:

error C2440: 'static_cast' : cannot convert from 'double' to 'MyEnum' 错误C2440:'static_cast':无法从'double'转换为'MyEnum'

  Conversions between enumeration and floating point values are no longer allowed 

And this MSDN article seems to confirm this by not mentioning floating-point types and explicitly stating 'integral' value: 这篇MSDN文章似乎通过不提及浮点类型并明确声明“整数”值来证实这一点:

The static_cast operator can explicitly convert an integral value to an enumeration type. static_cast运算符可以显式地将整数值转换为枚举类型。 If the value of the integral type does not fall within the range of enumeration values, the resulting enumeration value is undefined. 如果整数类型的值不在枚举值的范围内,则生成的枚举值未定义。

So it appears that there is a significant difference here between VS 2010 and the other compilers. 因此,VS 2010与其他编译器之间似乎存在显着差异。 I am wondering whether this is something that can be bypassed in VS 2010? 我想知道这是否可以在VS 2010中被绕过? Is it a newer feature of the language that VS 2010 simply doesn't support? 它是VS 2010根本不支持的语言的新功能吗? However I query this as the error message says "no longer allowed", implying it's explicitly disallowed. 但是我查询这个错误信息显示“不再允许”,暗示它被明确禁止。

I know of a workaround - instead of casting to an enum (with Extractor<MyEnum> ), I can use an Extractor<int> instead, and then simply assign this to the target MyEnum variable. 我知道一个解决方法 - 而不是强制转换为枚举(使用Extractor<MyEnum> ),我可以使用Extractor<int> ,然后将其分配给目标MyEnum变量。 However this template is actually used as part of a larger system that calls wrapped functions, and in this case the wrapped function takes a MyEnum value. 但是,此模板实际上用作调用包装函数的较大系统的一部分,在这种情况下,包装函数采用MyEnum值。 This prevents the template from matching properly as the ValueType parameter is actually picked up automatically from the signature of the wrapped function. 这可以防止模板正确匹配,因为ValueType参数实际上是从包装函数的签名中自动获取的。

Alternatively, is it possible to write a template specialization of Extractor that matches enum types only? 或者,是否可以编写仅与enum类型匹配的Extractor模板特化? Then I can cast to an integral type first. 然后我可以先演成一个整体类型。 Or maybe the base template could always cast to an int first, then I could write a floating-point specialization that doesn't do this - but I'm not sure how to write a template that catches all floating-point types (float, double, ...). 或者也许基本模板总是可以首先转换为int,然后我可以编写一个不执行此操作的浮点专门化 - 但我不确定如何编写捕获所有浮点类型的模板(float,加倍,...)。

I'm pretty sure Visual Studio-2010 supports <type_traits> . 我很确定Visual Studio-2010支持<type_traits> You can use std::enable_if along with std::is_enum . 您可以将std::enable_ifstd::is_enum一起使用。

template <typename ValueType, typename Enable = void>
class Extractor {
 public:
  ValueType extract(API_Secret value);
};

template <typename ValueType>
class Extractor<ValueType, typename std::enable_if<std::is_enum<ValueType>::value>::type>
{
 ...
};


You can do the same to match floating point types using std::is_floating_point . 您可以使用std::is_floating_point来匹配浮点类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM