2013-02-11 7 views
6

Xcode 4.5とLLVM 3.0でうまく動作するテンプレートコードがありますが、VS 2010 Express C++ツールチェーン(v 10.0.30319.1)で失敗します。浮動小数点値を列挙型にキャストしていますが、VS 2010ではキャストできません

私は制御できないサードパーティの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); 
    } 
}; 

:それは唯一のAPI関数によって解釈することができブラックボックス「塊」としての私のコードに値を提供し

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); 

を今Xcodeの、LLVMとVS間の差のためにXcodeの& LLVMで2010年、次の(完全なプログラムの一部として)コンパイルされます:

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

すなわちクラステンプレートはstatic_castを浮動小数点数から列挙型に変換します。これは、正常に動作するようです、とthis pageの説明セクションでは、これが有効であることを示唆している:

8)整数、浮動小数点、または列挙型は、任意の列挙型に変換できる場合(結果が指定されていません式の値は、列挙の基になる型に変換され、ターゲット列挙値のいずれか)VS2010でしかし

ないが、次のコンパイラエラーが発生した:

エラーC2440:「static_castを」:「MyEnum」

 Conversions between enumeration and floating point values are no longer allowed 

に「ダブル」から変換し、このMSDN articleは浮動小数点型に言及し、明示的に「整数」の値を記述しないことによってこれを確認するように見えることはできません。

static_cast演算子は、積分値を列挙型に明示的に変換できます。整数型の値が列挙型の値の範囲内にない場合、結果の列挙型の値は未定義です。

ここで、VS 2010と他のコンパイラとの間には大きな違いがあるようです。私はこれがVS 2010でバイパスできるかどうか疑問に思っていますか? VS 2010がサポートしていない言語の新しい機能ですか?しかし、私はエラーメッセージが "許可され​​なくなりました"と言ってこれを照会しますが、明示的に許可されていないことを意味します。

私は回避策を知っています - 列挙型(Extractor<MyEnum>)にキャストする代わりに、代わりにExtractor<int>を使用して、これを単にターゲットのMyEnum変数に割り当てることができます。しかし、このテンプレートは、ラップされた関数を呼び出す大規模なシステムの一部として実際に使用されます。この場合、ラップされた関数はMyEnum値をとります。これにより、ValueTypeパラメータが実際にラップされた関数のシグネチャから自動的に取得されるため、テンプレートが適切に一致しなくなります。

また、enumタイプに一致するExtractorのテンプレート特殊化を記述することは可能ですか?次に、一体型にキャストすることができます。または、基本テンプレートを常に最初にintにキャストできたら、これをしない浮動小数点特殊化を書くことができますが、浮動小数点型をすべてキャッチするテンプレートを書き込む方法がわかりません(浮動小数点型、ダブル、...)。

+1

例コードのマイナーなタイプミス: 'int v1 = e1.extract(secret1);'は 'double v1 = e1.extract(secret1);'でなければなりません。 –

+0

@JesseChisholmありがとう、固定。 – meowsqueak

答えて

3

私はかなり確信していますVisual Studio-2010 supports <type_traits>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> 
{ 
... 
}; 


あなたはstd::is_floating_pointを使用して浮動小数点型と一致するように同じことを行うことができます。

+0

ありがとう、これは非常に有望に見えます。 enum-specializationの後、どのように補完テンプレートを指定するのですか?ここでEnableは* not * enumですか? (すなわち元のテンプレート)。編集:ああ、それはstd :: enable_if <!std :: is_enumと同じくらい簡単です... - 素晴らしい、それは、あなたに感謝します。 – meowsqueak

+0

Xcodeのツールチェインを除いて、どこでも動作します - はありません。を実行しなければなりません。そして、std :: enable_ifに関するエラーが__gnu_cxx :: __ enable_ifになる必要があります。これを解決する方法? boostのtype_traitsを代わりに使うのは意味がありますか? – meowsqueak

+0

私はこれを直接ここに記述する質問を投稿しました - http://stackoverflow.com/questions/14823832 – meowsqueak