2015-02-15 13 views
11

यह Undefined reference to static constexpr char[][] पर एक अनुवर्ती प्रश्न है।constexpr स्थिर सदस्य चर के साथ अजीब व्यवहार

निम्न प्रोग्राम बनाता है और ठीक चलाता है।

#include <iostream> 

struct A { 
    constexpr static char dict[] = "test"; 

    void print() { 
     std::cout << A::dict[0] << std::endl; 
    } 
}; 

int main() { 
    A a; 
    a.print(); 
    return 0; 
} 

हालांकि, अगर मैं A::print() बदलें:

void print() { 
     std::cout << A::dict << std::endl; 
    } 

मैं जी में ++ 4.8.2 निम्नलिखित लिंकर त्रुटि मिलती है।

constexpr char A::dict[]; 
वर्ग परिभाषा के बाहर

:

 
/tmp/cczmF84A.o: In function `A::print()': 
socc.cc:(.text._ZN1A5printEv[_ZN1A5printEv]+0xd): undefined reference to `A::dict' 
collect2: error: ld returned 1 exit status 

लिंकर त्रुटि एक पंक्ति जोड़कर हल किया जा सकता।

हालांकि, यह मुझे स्पष्ट नहीं है कि सरणी के सदस्यों में से किसी एक का उपयोग करने से लिंकर त्रुटि का कारण बनता है जब एरे का उपयोग करते समय लिंकर त्रुटि होती है।

+0

क्योंकि पूर्व को एक मूल्य की आवश्यकता है, जबकि बाद वाले को एक पते की आवश्यकता है? –

+0

दोनों ओडीआर-उपयोग हैं, मुझे लगता है। आपको 'dict [0] 'मामले में भाग्यशाली (अन) भाग्यशाली मिला। –

+1

क्लैंग आपके पहले संस्करण को पसंद नहीं करता है, वही अपरिभाषित संदर्भ संदेश आपके दूसरे संस्करण के साथ देता है। – hvd

उत्तर

7

मानक को परिभाषा प्रदान करने में विफलता के लिए किसी भी निदान की आवश्यकता नहीं होती है जहां किसी की आवश्यकता होती है।

3,2 एक परिभाषा नियम [basic.def.odr]

4 हर कार्यक्रम हर गैर इनलाइन समारोह या चर ओडीआर से इस्तेमाल किया है कि कार्यक्रम में है कि के ठीक एक परिभाषा शामिल होगा; कोई निदान की आवश्यकता नहीं है। [...]

इसका मतलब है कि कार्यान्वयन को ऐसे चरों तक पहुंच को अनुकूलित करने की अनुमति है, और यह आपके पहले मामले में जीसीसी के साथ हो रहा है।

दोनों जीसीसी और क्लैंग ने फैसला किया है कि वे एक सतत उपयोगकर्ता अनुभव पसंद करते हैं, जहां लापता परिभाषाओं के बारे में त्रुटि संदेश अनुकूलन स्तर पर निर्भर नहीं हैं। आमतौर पर, इसका मतलब है कि किसी भी गायब परिभाषा में त्रुटि संदेश होता है। हालांकि, इस मामले में, जीसीसी त्रुटि से परहेज करते हुए, -O0 पर भी कुछ न्यूनतम अनुकूलन कर रहा है।

लेकिन कार्यक्रम, एक त्रुटि किसी भी तरह से है, क्योंकि यहां तक ​​कि A::dict[0] एक ओडीआर उपयोग है:

3,2 एक परिभाषा नियम [basic.def.odr]

3 चर x जिसका नाम संभावित रूप से मूल्यांकन की गई अभिव्यक्ति के रूप में प्रकट होता है exex द्वारा odr-used है जब तक कि lvalue-to-rvalue रूपांतरण (4.1) से x लागू करने के लिए निरंतर अभिव्यक्ति (5.1 9) उत्पन्न होती है जो किसी भी गैर-तुच्छ कार्यों का आह्वान नहीं करती है और, यदि x एक वस्तु है, ex एक अभिव्यक्ति e अभिव्यक्ति के संभावित परिणामों के सेट का एक तत्व है, जहां या तो lvalue-to-rvalue रूपांतरण (4.1) e पर लागू होता है, या e एक त्याग-मूल्य अभिव्यक्ति (क्लॉज 5) है। [...]

A::dict के उपयोग lvalue करने वाली rvalue रूपांतरण को शामिल नहीं करता है, यह सरणी-टू-सूचक रूपांतरण है, तो अपवाद लागू नहीं होता शामिल है।

+2

इस बारे में चर्चा से लाभ हो सकता है कि क्यों 'ए :: dict [0] 'एक odr-use है। –

+0

@ टी.सी. सहमत, और किया। – hvd

+0

@ टी.सी. यह अब और नहीं है। – Columbo

0

@hvd in his answer द्वारा दी गई जानकारी के अलावा ...

C++ से ड्राफ्ट स्टैंडर्ड N3337 (जोर मेरा):

9.4.2 स्टेटिक डेटा सदस्यों

3 यदि एक गैर-अस्थिर const static डेटा सदस्य अभिन्न या गणना प्रकार का है, तो कक्षा परिभाषा में इसकी घोषणा ब्रेस-या-बराबर-प्रारंभकर्ता निर्दिष्ट कर सकती है जिसमें प्रत्येक प्रारंभकर्ता-खंड है जो असाइनमेंट-अभिव्यक्ति एक निरंतर अभिव्यक्ति (5.1 9) है। शाब्दिक प्रकार के static डेटा सदस्य को constexpr विनिर्देशक के साथ कक्षा परिभाषा में घोषित किया जा सकता है; यदि हां, तो इसकी घोषणा ब्रेस-या-बराबर-प्रारंभकर्ता निर्दिष्ट करेगी जिसमें प्रत्येक प्रारंभकर्ता-खंड जो असाइनमेंट-अभिव्यक्ति एक निरंतर अभिव्यक्ति है। [नोट: इन दोनों मामलों में, सदस्य निरंतर अभिव्यक्तियों में दिखाई दे सकता है। - एंड नोट] सदस्य को अभी भी नामस्थान स्कोप में परिभाषित किया जाएगा यदि यह प्रोग्राम में ओडीआर-प्रयुक्त (3.2) है और नामस्थान स्कोप परिभाषा में प्रारंभकर्ता शामिल नहीं होगा।

यह देखते हुए कि A::data ओडीआर रूप से प्रयुक्त अभिव्यक्ति A::data[0] में है, मानक के अनुसार, यह एक नाम स्थान दायरे में परिभाषित किया जाएगा। तथ्य यह है कि जी ++ A::data के बिना सफलतापूर्वक प्रोग्राम बनाने में सक्षम है, जो नामस्थान स्थान में परिभाषित किया गया है, प्रोग्राम को सही नहीं बनाता है। मानक अनुपालन करने के लिए, A::data परिभाषित किया जाएगा।

+0

हू, आप सही हैं, वह भी है। वह * नहीं कहता है "कोई निदान आवश्यक नहीं है", इसलिए आप वैध रूप से तर्क दे सकते हैं कि जीसीसी उस नियम के उल्लंघन का निदान करने में विफल होने के लिए छोटी है। (लेकिन अधिक संभावना है कि यह शब्द में एक नाइट है, और एक निदान की आवश्यकता नहीं है।) – hvd

+0

@ एचवीडी, मुझे लगता है कि "कोई डायग्नोस्टिक आवश्यक" अभी भी लागू नहीं होता है क्योंकि यह संदर्भ "ओडीआर-प्रयुक्त (3.2)" , –

+0

हाँ, लेकिन ओडीआर-प्रयुक्त सिर्फ [3.2] पी 3 को संदर्भित करता है, जो निर्दिष्ट करता है कि कौन से वेरिएबल ओडीआर-प्रयुक्त होते हैं, न कि [3.2] पी 4, जिसके लिए उन चर के लिए परिभाषा की आवश्यकता होती है जो ओडीआर-प्रयुक्त होते हैं। [3।2] पी 3 वह जगह है जहां "odr-used" इटालिक्स में दिखाई देता है, और इटालिक्स में यह उपस्थिति का अर्थ है कि यह परिभाषित करता है कि "odr-used" शब्द का अर्थ क्या है। – hvd

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