2012-01-16 20 views
19

यह एक बहुत ही बुनियादी सवाल है लेकिन मुझे समझ में नहीं आता कि नीचे दिया गया कोड जीसीसी 4.6.1 पर संकलित क्यों नहीं करता है। यह SP1 के साथ वी.एस. 2008 को संकलित करता है:अजीब जीसीसी संकलन त्रुटि (सरल उदाहरण शामिल)

#include <iostream> 

class MyClass 
{ 
public: 
    const static int MinValue = -1000; 
    const static int MaxValue = 1000; 
}; 

void printValue(int i) 
{ 
    std::cout << i << std::endl; 
} 

int main(int argc, char** argv) 
{ 
    printValue(MyClass::MinValue); 
    printValue(MyClass::MaxValue); 
    printValue(argc < 42 ? MyClass::MinValue : MyClass::MaxValue); //This line gives the error 
} 

जीसीसी का कहना है:

[email protected]:~/temp$ g++ test.cpp 
/tmp/ccN2b95G.o: In function `main': 
test.cpp:(.text+0x54): undefined reference to `MyClass::MinValue' 
test.cpp:(.text+0x5c): undefined reference to `MyClass::MaxValue' 
collect2: ld returned 1 exit status 

हालांकि, अगर मैं तो यह बनाता है और सही ढंग से चले 'printValue' के लिए तीसरी कॉल बाहर ले। तो यह '?' के साथ कुछ करने के लिए है ऑपरेटर ... क्या यह इस तरह उपयोग करने के लिए मान्य नहीं है? इसके अलावा, अगर मैं 'argc < 42' को 'सत्य' या 'झूठी' के साथ प्रतिस्थापित करता हूं तो यह भी ठीक बनाता है।

कोई विचार ?!

+1

कंपाइलर की बग? –

+2

@VJovic: नहीं - यह एक परिभाषा होनी चाहिए यदि यह * odr-used * है, यह तब तक है जब तक कि यह एक ऐसा ऑब्जेक्ट नहीं है जो निरंतर अभिव्यक्ति में दिखाई देने के लिए आवश्यकताओं को पूरा करता है और लैवल्यू-टू-रावल्यू रूपांतरण तुरंत लागू होता है " । फ़ंक्शन तर्कों के लिए यह मामला है, लेकिन सशर्त ऑपरेटर के परिणाम के लिए नहीं जब स्थिति निरंतर अभिव्यक्ति नहीं होती है और नतीजा एक अंतराल होता है। –

+1

@ माइकसेमोर: मुझे लगता है कि मैंने ओडीआर-प्रयुक्त और टर्नरी ऑपरेटरों के बारे में कुछ मेल पढ़े हैं, क्या आप इसे उचित उत्तर में विस्तारित करना चाहते हैं? मैं वास्तव में यहाँ subtlety समझना चाहता हूँ। –

उत्तर

7

आप वर्ग घोषणा के बाहर अपने स्थिर सदस्यों परिभाषित करने की जरूरत:

class MyClass 
{ 
public: 
    const static int MinValue; 
    const static int MaxValue; 
}; 


//implementation file 
const int MyClass::MinValue = -1000; 
const int MyClass::MaxValue = 1000; 
+1

यह स्पष्ट नहीं करता है कि आखिरी 'printValue' क्यों विफल रहा है। – greatwolf

+4

असल में मैंने सोचा कि केवल गैर-अभिन्न प्रकारों पर लागू होता है? या मैं इसे किसी और चीज़ से भ्रमित कर रहा हूं। साथ ही, वॉल्यू संकलन प्रिंट करने के लिए पहले दो कॉल क्यों करते हैं? – PolyVox

+0

@VictorT। ऐसा करता है, क्योंकि आप अस्थायी रूप से परिभाषित एक स्थिर सदस्य तक पहुंचने का प्रयास कर रहे हैं। –

0

मैं एक अंग पर बाहर जाना और कहते हैं कि यह शायद संस्करण उपयोग कर रहे के साथ एक संकलक बग है करने के लिए जा रहा हूँ। जैसा कि एज़ा ने अपनी टिप्पणी में उल्लेख किया है, जीसीसी-4.5.1 इसे gcc-4.3.4 के रूप में ठीक बनाता है। मैंने अभी भी CLang 2.9 के साथ इसका परीक्षण किया और यह भी कोड स्वीकार करता है।

वैकल्पिक रूप से, आप स्थिरांक के बजाय अपने न्यूनतम/अधिकतम मानों को enums के साथ परिभाषित कर सकते हैं। यह कुछ टाइपिंग की बचत होगी: अगर है ओडीआर-प्रयोग किया जाता है

#include <iostream> 

class MyClass 
{ 
public: 
    enum { MinValue = -1000, MaxValue = 1000 }; 
}; 

void printValue(const int i) 
{ 
    std::cout << i << std::endl; 
} 

int main(int argc, char** argv) 
{ 
    printValue(MyClass::MinValue); 
    printValue(MyClass::MaxValue); 
    printValue(argc < 42 ? MyClass::MinValue : MyClass::MaxValue); 
} 
+0

+1 यूप, मैंने 5 मिनट पहले जीसीसी 4.3.4 पर भी जांच की थी। काफी दिलचस्प। – lapk

+0

प्रारंभ में मैंने माना कि यह एक कंपाइलर बग था, लेकिन माइक सेमुर के स्पष्टीकरण को देखते हुए, ऐसा लगता है कि यह सही हो सकता है। इसके बजाए जीसीसी-4.5.1 और 4.3.4 अमान्य कोड स्वीकार कर रहे हैं, जिसका अर्थ है कि एक बग था जिसे अब तय किया गया है? – PolyVox

+0

संदर्भ के लिए, क्लैंग 3.0 कोड स्वीकार करता है। –

18

"एक परिभाषा नियम" के अनुसार, एक चर ठीक एक परिभाषा होनी चाहिए। यह सी ++ 11 मानक द्वारा परिभाषित किया गया है:

3,2/2 एक चर या गैर अतिभारित समारोह जिसका नाम एक संभावित मूल्यांकन अभिव्यक्ति के रूप में प्रकट होता है ओडीआर से इस्तेमाल किया जब तक कि यह एक वस्तु है कि के लिए आवश्यकताओं को संतुष्ट करता है एक निरंतर अभिव्यक्ति में दिखाई दे रहा है और lvalue-to-rvalue रूपांतरण तुरंत लागू किया जाता है।

और ओडीआर ही:

3,2/3 हर कार्यक्रम हर गैर इनलाइन समारोह या चर कि है कि इस कार्यक्रम में ओडीआर रूप से प्रयुक्त की ठीक एक परिभाषा शामिल होगा; कोई निदान की आवश्यकता नहीं है।

समारोह कॉल तर्क के रूप में, वे नहीं हैं ओडीआर रूप से प्रयुक्त: वे अपने घोषणा में निर्दिष्ट एक मूल्य के साथ स्थिरांक हैं, और इसलिए एक निरंतर अभिव्यक्ति में प्रदर्शित कर सकते हैं; और वे मूल्य से पारित होते हैं, और इसलिए तुरंत राजस्व में परिवर्तित हो जाते हैं।

यह तब नहीं है जब उनका सशर्त अभिव्यक्ति में उपयोग किया जाता है। चूंकि दोनों lvalues ​​एक ही प्रकार की चर्चा करते हुए कर रहे हैं, सशर्त अभिव्यक्ति का परिणाम एक lvalue हो जाएगा, सशर्त ऑपरेटर को परिभाषित नहीं बल्कि जटिल नियमों में से एक के अनुसार:

5,16/4, द्वितीय और तृतीय ऑपरेंड हैं एक ही मूल्य श्रेणी के glvalues ​​और एक ही प्रकार है, परिणाम उस प्रकार और मूल्य श्रेणी का है।

(यह नियम (a?b:c)=d जैसे अभिव्यक्तियों की अनुमति देता है।)

तो स्थिरांक स्वयं को तुरंत राजस्व में परिवर्तित नहीं किया जाता है, और सशर्त अभिव्यक्ति रनटाइम की स्थिति के कारण निरंतर अभिव्यक्ति में प्रकट नहीं हो सकती है; इसलिए, वे odr-used हैं, और इसलिए एक परिभाषा की आवश्यकता है।

जैसा कि आप ध्यान देते हैं, एक स्थिर अभिव्यक्ति को स्थिति बदलना लिंक त्रुटि को हल करता है; तो एक स्थिर प्रकार के प्रकार बदल जाएगा। लेकिन अभिव्यक्ति के रूप में यह खड़ा है कि उनके पास एक (और केवल एक) अनुवाद इकाई में परिभाषा है:

const int MyClass::MinValue; 
const int MyClass::MaxValue; 
+0

धन्यवाद माइक। आश्चर्यजनक रूप से पर्याप्त, क्लैंग 3.0 अभी भी कोड स्वीकार करता है। –

+0

+1 अच्छी जानकारी। एक तरफ ध्यान दें, जी, मैं इस प्रश्न के उत्तर पर अपने सभी '1' भत्ता खर्च करने वाला हूं ... मुझे उम्मीद है कि एक अन्य सूचनात्मक उत्तर नहीं होगा, जिसे मुझे' + निष्पक्षता से 1'। – lapk

+0

आप जोड़ सकते हैं कि एक परिभाषा नियम के उल्लंघन "कोई निदान आवश्यक नहीं है" (एक अवधारणा जिसे मानक परिभाषित नहीं किया जाता है, लेकिन जो अनिवार्य रूप से अपरिभाषित व्यवहार के लिए होता है, क्योंकि मानक "किसी भी स्पष्ट परिभाषा के वर्णन को छोड़ देता है व्यवहार ") –

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