2013-02-11 54 views
6

साथ मैं कुछ टेम्पलेट कोड कि Xcode 4.5 और LLVM 3.0 के साथ ठीक काम करता है, लेकिन VS 2010 एक्सप्रेस सी ++ toolchain के साथ विफल रहता है (v 10.0.30319.1)।सी ++ एक enum करने के लिए एक चल बिन्दु मूल्य कास्टिंग - लेकिन नहीं VS 2010

मुझे लगता है मैं कोई नियंत्रण नहीं है कि किसी तीसरे पक्ष के एपीआई का उपयोग कर रहा हूँ।

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

फिर, बाद में: Xcode, LLVM और वी.एस. के बीच अंतर के लिए अब

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

यह मान ब्लैक बॉक्स 'धब्बे' के रूप में अपने कोड है कि केवल एपीआई कार्यों से व्याख्या की जा सकती करने के लिए प्रदान करता है 2010 Xcode & LLVM साथ ही, नीचे (पूर्ण कार्यक्रम के हिस्से के रूप में) संकलन होगा:

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

Ie कक्षा टेम्पलेट 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 ऑपरेटर को स्पष्ट रूप से गणना प्रकार के एक अभिन्न मूल्य बदल सकते हैं। यदि अभिन्न प्रकार का मान गणना मूल्यों की सीमा के भीतर नहीं आता है, परिणामी गणना मूल्य अपरिभाषित है।

तो ऐसा लगता है कि वीएस 2010 और अन्य कंपाइलर्स के बीच यहां एक महत्वपूर्ण अंतर है। मैं सोच रहा हूं कि यह ऐसा कुछ है जिसे वीएस 2010 में छोड़ दिया जा सकता है? क्या यह भाषा की एक नई विशेषता है कि वीएस 2010 बस समर्थन नहीं करता है? हालांकि मैं इसे पूछता हूं क्योंकि त्रुटि संदेश "अब अनुमति नहीं है" कहता है, जिसका अर्थ यह स्पष्ट रूप से अस्वीकृत है।

मुझे एक कामकाज के बारे में पता है - एक enum (Extractor<MyEnum> के साथ) कास्टिंग करने के बजाय, मैं इसके बजाय Extractor<int> का उपयोग कर सकता हूं, और उसके बाद इसे लक्ष्य MyEnum चर के लिए असाइन कर सकता हूं। हालांकि इस टेम्पलेट को वास्तव में एक बड़े सिस्टम के हिस्से के रूप में उपयोग किया जाता है जो लपेटा हुआ फ़ंक्शंस कहता है, और इस मामले में लपेटा हुआ फ़ंक्शन एक MyEnum मान लेता है। यह टेम्पलेट को ठीक से मिलान करने से रोकता है क्योंकि ValueType पैरामीटर वास्तव में लपेटा हुआ फ़ंक्शन के हस्ताक्षर से स्वचालित रूप से उठाया जाता है।

वैकल्पिक रूप से, यह एक्सट्रैक्टर कि enum प्रकार केवल मेल खाता है की एक टेम्पलेट विशेषज्ञता लिखने के लिए संभव है? तो मैं पहले एक अभिन्न प्रकार के लिए जा सकते हैं।या हो सकता है कि आधार टेम्पलेट हमेशा पहले एक int में डाला जा सके, तो मैं एक फ्लोटिंग-पॉइंट विशेषज्ञता लिख ​​सकता हूं जो ऐसा नहीं करता है - लेकिन मुझे यकीन नहीं है कि एक टेम्पलेट कैसे लिखना है जो सभी फ़्लोटिंग-पॉइंट प्रकारों को पकड़ता है (फ्लोट, डबल, ...)।

+1

उदाहरण कोड में मामूली टाइपो: 'int v1 = e1.extract (secret1);' डबल v1 = e1.extract (secret1) होना चाहिए; 'इसके बजाय। –

+0

@ जेसे चिश्ल्म धन्यवाद, तय। – meowsqueak

उत्तर

3

मुझे यकीन है कि Visual Studio-2010 supports <type_traits> है। आप के साथ std::is_enum के साथ std::enable_if का उपयोग कर सकते हैं।

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? (यानी मूल टेम्पलेट)। संपादित करें: ओह, यह std :: enable_if meowsqueak

+0

तो बंद करें ... एक्सकोड के टूलचेन को छोड़कर हर जगह काम करता है - , करना है और फिर मुझे std :: enable_if के बारे में त्रुटियों का पूरा गुच्छा मिलता है __gnu_cxx :: __ enable_if - क्या कोई पोर्टेबल है इसे हल करने का तरीका? क्या इसके बजाय बूस्ट के टाइप_टिट्स का उपयोग करना समझदारी होगी? – meowsqueak

+0

मैंने इसे सीधे यहां संबोधित करने के लिए एक प्रश्न पोस्ट किया है - http://stackoverflow.com/questions/14823832 – meowsqueak