2013-02-27 103 views
5

मैं की तरह एक enum है:सी ++ 11 प्रकार एनम मैपिंग के लिए?

enum E 
{ 
    TYPE_FLOAT, 
    TYPE_CHAR, 
    TYPE_INT 
} 

और मैं एक प्रकार की तरह के लिए उपयुक्त ई प्राप्त करने के लिए एक संकलन समय मानचित्रण बनाना चाहते हैं:

template<class T> struct GetE; 

template<> struct GetE<float> { static constexpr E type = TYPE_FLOAT; }; 
template<> struct GetE<char> { static constexpr E type = TYPE_CHAR; }; 
template<> struct GetE<int> { static constexpr E type = TYPE_INT; }; 
:

GetE<float> // returns TYPE_FLOAT 
GetE<char> // returns TYPE_CHAR 
GetE<int> // returns TYPE_INT 

मैं के बारे में सोचा

लेकिन मुझे त्रुटियां मिल रही हैं जैसे:

undefined reference to `GetE<int>::type' 

ऐसा करने का सबसे अच्छा तरीका क्या है? और त्रुटि क्यों?

उत्तर

6

पर एक लिंक है यह इस बात पर निर्भर करता है कि आप इनका उपयोग कैसे करते हैं निरंतर अभिव्यक्तियां

ओडीआर (एक परिभाषा नियम) कहा गया है कि

(§3.2/2) [...] एक चर जिसका नाम एक संभावित मूल्यांकन अभिव्यक्ति के रूप में प्रकट होता है ओडीआर से इस्तेमाल किया है, जब तक यह एक है ऑब्जेक्ट जो निरंतर अभिव्यक्ति (5.1 9) में दिखाई देने के लिए आवश्यकताओं को पूरा करता है और lvalue-to-rvalue रूपांतरण (4.1) तुरंत लागू होता है। [...]

(और फिर, विशेष नियम, अपवाद और अपवादों की अपवाद के बहुत सारे पालन करें।)

किसी भी चर है कि ओडीआर से इस्तेमाल किया, ठीक एक परिभाषा होनी चाहिए। आपके निरंतर अभिव्यक्तियों में एक घोषणा है, लेकिन परिभाषा नहीं है, इसलिए यह तब तक ठीक हो जाता है जब तक कि आप उनमें से एक का उपयोग न करें।

उदाहरण के लिए, निम्नलिखित में अच्छी तरह से चला जाता है:

int main() { 
    E e = GetE<float>::type; 
    return 0; 
} 

लेकिन यह नहीं करता है:

क्योंकि
void f(const E &) 
{ } 

int main() { 
    f(GetE<float>::type); 
    return 0; 
} 

f एक (स्थिरांक) संदर्भ की आवश्यकता है, इसलिए lvalue करने वाली rvalue रूपांतरण नहीं किया जा सकता तुरंत लागू, इसलिए यह एक odr-use का गठन करता है। संकलक शिकायत करेगा कि यह एक परिभाषा याद करता है।

(टिप्पणी। शाफिक यघमोर को मिली (टिप्पणियां देखें), यदि संकलक ऑप्टिमाइज़ेशन का उपयोग करता है तो आपको कोई शिकायत नहीं मिल सकती है, क्योंकि संदर्भों को अनुकूलित किया जा सकता है। कंपाइलर शिकायत को पुन: उत्पन्न करने के लिए, -O0 ध्वज (या इसी तरह के, कंपाइलर के आधार पर)।

समस्या को हल करने के लिए, आवश्यक परिभाषा सामान्य तरीके से प्रदान की जा सकती है, यानीstruct परिभाषा के बाहर:

constexpr E GetE<float>::type; 
constexpr E GetE<char>::type; 
constexpr E GetE<int>::type; 

लेकिन इस के बाद से सीपीपी (नहीं हेडर फाइल), तो आपको दो अलग अलग स्थानों में घोषणाओं और परिभाषाओं बनाए रखने के लिए है, जो होने पहुंच जाएंगे में होती हैं करने के लिए होगा बोझिल।

समाधान तुम सिर्फ अपनी टिप्पणी में सुझाव दिया है, यानि कि एक constexpr (और इनलाइन) समारोह को परिभाषित, सही लगता है:

template <class T> constexpr E GetE(); 

template <> constexpr E GetE<float>() 
{ return TYPE_FLOAT; } 

template <> constexpr E GetE<char>() 
{ return TYPE_CHAR; } 

template <> constexpr E GetE<int>() 
{ return TYPE_INT; } 

void f(const E &) 
{ } 

int main() { 
    E e = GetE<float>(); 

    f(GetE<float>()); 

    return 0; 
} 
+1

हाँ यह उचित लगता है। मैं 'tmpl ई गेटई()' जैसे फ़ंक्शन टेम्पलेट का उपयोग करने के लिए बदल गया हूं और फिर इसके बजाय विशेषज्ञता और इसे ठीक कर दिया है। धन्यवाद। –

+1

@jogojapan मैं आपकी टिप्पणी से सीखने की कोशिश कर रहा हूं लेकिन मुझे कोड के अंतिम भाग का उपयोग करके कोई त्रुटि नहीं दिखाई दे रही है: http://liveworkspace.org/code/4oTEis मुझे क्या याद आ रही है? धन्यवाद –

+1

@ShafikYaghmour यह '-O2' कंपाइलर ध्वज की वजह से है। यह संदर्भों को दूर करता है। अच्छी टिप्पणी, हालांकि, मैं इसका उत्तर में उल्लेख करूँगा। – jogojapan

1

स्टेटिक सदस्य चर वर्ग दायरे से बाहर परिभाषित होने की जरूरत:

class C { 
    const static int x = 5; 
}; 

decltype(C::x) C::x; 
+0

यहां तक ​​कि अपने 'constexpr' तो क्या होगा? वह अजीब है। –

+0

ठीक है, जीसीसी 4.7 पर यह काम करता है। शायद यह सिर्फ आपका कंपाइलर है? 412.2 का उपयोग कर –

+0

भी। –

1

हो सकता है कि क्योंकि आप enum परिभाषा के बाद अर्धविराम डाल करने के लिए भूल गया, यह मेरे लिए काम करता LiveWorkSpace में:

#include <iostream> 

enum E 
{ 
    TYPE_FLOAT, 
    TYPE_CHAR, 
    TYPE_INT 
} ; 

template<class T> struct GetE; 

template<> struct GetE<float> { static constexpr E type = TYPE_FLOAT; }; 
template<> struct GetE<char> { static constexpr E type = TYPE_CHAR; }; 
template<> struct GetE<int> { static constexpr E type = TYPE_INT; }; 

int main() 
{ 
    std::cout << GetE<int>::type << std::endl ; 
} 

यहां कोड http://liveworkspace.org/code/nHqUe $ 6

+0

वास्तविक कोड में नहीं मेरे पास अर्धविराम है। हमम अजीब मैं भी 4.7.2 का उपयोग कर रहा हूँ। यकीन नहीं है कि क्या हो रहा है। धन्यवाद। –

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^