6

Xcode4.5とLLVM3.0で正常に動作するテンプレートコードがいくつかありますが、VS 2010 Express C ++ツールチェーン(v 10.0.30319.1)では失敗します。

制御できないサードパーティのAPIを使用しています。これは、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_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 2010の違いについて説明します。XcodeとLLVMでは、以下がコンパイルされます(完全なプログラムの一部として)。

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

つまり、クラステンプレートは、static_cast使用して浮動小数点数から列挙型に変換します。これは正常に機能しているようです。このページの説明セクションでは、これが有効であることが示されています。

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

ただし、VS2010では、次のコンパイラエラーが発生します。

エラーC2440:'static_cast':'double'から'MyEnum'に変換できません

     Conversions between enumeration and floating point values are no longer allowed

そして、このMSDNの記事は、浮動小数点型については言及せず、「整数」値を明示的に示すことで、これを確認しているようです。

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

したがって、ここではVS2010と他のコンパイラとの間に大きな違いがあるようです。これがVS2010でバイパスできるものかどうか疑問に思っていますか?VS 2010が単にサポートしていない言語の新しい機能ですか?ただし、エラーメッセージに「もう許可されていません」と表示されているため、これをクエリします。これは、明示的に許可されていないことを意味します。

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

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

4

1 に答える 1

3

Visual Studio-2010 がサポートし<type_traits>ていると確信しています。std::enable_ifと併用できますstd::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

于 2013-02-11T22:19:04.653 に答える