2010-01-05 18 views
7

निम्नलिखित कोड पर विचार करें:सी ++ स्पष्ट निर्माणकर्ता और iterators

चाहिए ऊपर संकलन? मेरी भावना यह है कि कन्स्ट्रक्टर को explicit चिह्नित करने के कारण यह नहीं होना चाहिए।

माइक्रोसॉफ्ट विज़ुअल सी ++ सहमत हैं, एक स्पष्ट त्रुटि संदेश दे रही है: cannot convert from 'int' to 'const A'; Constructor for struct 'A' is declared 'explicit'

हालांकि, Comeau's online compiler का उपयोग कर, कोड सफलतापूर्वक संकलित करता है।

कौन सा सही है?

संपादित करें:

दिलचस्प है, set को vector बदलते (ए के लिए एक operator < जोड़ने के बाद) एक त्रुटि देने के लिए दोनों compilers कारण बनता है।

हालांकि, vector<int> से map<int, int> और vector<A> से map<A, A> दोनों कंपेलरों को कोड स्वीकार करने का कारण बनता है!

+0

अप्रत्यक्ष रूप से यहां उत्तर दिया गया: http://stackoverflow.com/questions/1943228/implicit-constructor-conversion-works-on-explicit-vectorvector-only- कभी-कभी –

+1

मैंने अभी उस प्रश्न + उत्तर के आधार पर एक उत्तर लिखा है, लेकिन यह वास्तव में लागू नहीं होता है, क्योंकि 'std :: vector :: iterator' एक अभिन्न प्रकार नहीं है, और भरने वाले कन्स्ट्रक्टर को कॉल नहीं किया जा रहा है। तो मैंने इसे हटा दिया। मुझे लगता है कि मैं बस इतना कह सकता हूं कि मानक किसी भी कंटेनर कन्स्ट्रक्टर में * स्पष्ट रूपांतरण * प्रतिबंधित नहीं करता है। – Potatoswatter

+0

वीएस 2010 बीटा कॉमौ और जीसीसी के रूप में व्यवहार करता है। –

उत्तर

3

मैंने जीसीसी के एसटीएल कार्यान्वयन को देखा और इसके समान व्यवहार होना चाहिए। यहाँ पर क्यों।

  • एक vector के तत्वों एक सामान्य समारोह टेम्पलेट जो किसी भी दो प्रकार X और V स्वीकार करता है और कहता है new(p) X(v) जहां v एक V है (मैं थोड़ा टीका कर रहा हूँ) द्वारा प्रारंभ कर रहे हैं। यह स्पष्ट रूपांतरण की अनुमति देता है।
  • एक set या map के तत्वों _tree<T,…> के एक निजी सदस्य समारोह जो विशेष रूप से उम्मीद है एक T const & में पारित होने के लिए द्वारा प्रारंभ कर रहे हैं। इस सदस्य समारोह एक टेम्पलेट (एक टेम्पलेट का सदस्य होने से परे), नहीं है, इसलिए यदि प्रारंभिक मूल्य को T में स्पष्ट रूप से परिवर्तित नहीं किया जा सकता है, कॉल विफल हो जाता है। (फिर से मैं कोड को सरल बना रहा हूं।)

मानक को स्पष्ट रूपांतरण कार्य की आवश्यकता नहीं है या एक सीमा के साथ एक कंटेनर प्रारंभ करते समय अंतर्निहित रूपांतरण काम नहीं करता है। यह बस कहता है कि रेंज कंटेनर में कॉपी की गई है। निश्चित रूप से आपके उद्देश्य के लिए संदिग्ध।

आश्चर्यजनक इस तरह की अस्पष्टता मौजूद है, इस बात पर विचार करते हुए कि उन्होंने कुछ हफ्ते पहले the one I had जैसी समस्याओं के विचार में मानक को पहले ही परिष्कृत कर दिया है।

1

मुझे लगता है कि यह इस बात पर निर्भर करेगा कि std::vector<A> As(Iterator,Iterator) एसटीएल के आपके विशेष कार्यान्वयन में कैसे लागू किया जाता है।

+0

मानक पुस्तकालय का व्यवहार कार्यान्वयन पर निर्भर नहीं होना चाहिए। –

+1

फिर फिर, वहां स्थान (बहुत दुर्लभ) हैं जहां मानक को दो समकक्ष तरीकों से व्याख्या नहीं किया जा सकता है। –

0

इस कोड Comeau में संकलित करता है नहीं:

class Foo 
{ 
public: 
explicit Foo(int bar) 
{ 
} 
}; 

class Bar 
{ 
void DoStuff(Foo foo){ 

} 
void DoStuff2() 
{ 
    DoStuff(4); 
} 
}; 

त्रुटि संदेश:

"ComeauTest.c", line 16: error: no suitable constructor exists to convert from "int" 
      to "Foo" 
    DoStuff(4); 
      ^

1 error detected in the compilation of "ComeauTest.c". 

तो अल्पविकसित स्तर पर ऑनलाइन संकलक स्पष्ट कंस्ट्रक्टर्स का समर्थन करता है। वेक्टर/इटरेटर्स के साथ कुछ करना चाहिए।

संपादित हालांकि यह संकलित:

Foo foo = (Foo)5; 

कौन सा एक स्पष्ट रूपांतरण है, इसलिए कि ठीक है। मेरा अनुमान है कि कॉमौ वेक्टर क्लास कहीं भी कन्स्ट्रक्टर में एक स्पष्ट कलाकार है, जहां माइक्रोसॉफ्ट की लाइब्रेरी नहीं है।

अधिक स्पष्ट कंस्ट्रक्टर्स पर - http://www.glenmccl.com/tip_023.htm

0

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

+0

यदि निर्माता का उपयोग नहीं किया जा रहा है, तो हम एक int से ए में परिवर्तित कैसे कर रहे हैं? – user200783

+0

कुछ भी नहीं बनाया जा रहा है और कुछ भी परिवर्तित नहीं किया जा रहा है - दोनों वैक्टर खाली हैं –

+0

व्यवहार "वही" के निर्माण से पहले "इनट्स" वेक्टर में कुछ डालने पर समान होता है। – user200783

1

यह एक कठिन सवाल है, और ऐसा हो सकता है कि विजुअलस्टूडियो सही है और कमू गलत है (यह वास्तव में विश्वास करना मुश्किल लगता है)।

वचन के द्वारा मानक अगर पढ़ा शब्द, प्रतिलिपि निर्माता के संदर्भ में परिभाषित करता है कि वेक्टर निर्माता (उद्धरण देखें), और जिसका शाब्दिक अर्थ है कि वस्तु इटरेटर अपसंदर्भन द्वारा प्राप्त पहले प्रकार टी में परिवर्तित किया जाना चाहिए और तो कॉपी कन्स्ट्रक्टर कहा जाना चाहिए। इस बिंदु पर, एक स्पष्ट निर्माता के साथ कोड संकलित नहीं होना चाहिए।

दूसरी तरफ, कार्यान्वयन की उम्मीद करना उचित लगता है, दूसरी ओर, एक कन्स्ट्रक्टर को सीधे संदर्भित इटरेटर के रूप में लेने के लिए कॉल करने के लिए, जिस स्थिति में कन्स्ट्रक्टर कॉल स्पष्ट होगा और इस प्रकार कोड संकलित होना चाहिए।यह नीचे दिए गए उद्धरण में सटीक शब्द के खिलाफ जाना होगा, प्रतिलिपि निर्माता के रूप में एक निर्माता है कि प्रकार टी का एक उद्देश्य के लिए एक एकल संभवतः लगातार संदर्भ लेने के रूप में दिए गए प्रकार टी के लिए परिभाषित किया गया है

मैं सोच भी नहीं सकते किसी भी उचित तर्क को कमौ दृष्टिकोण का उपयोग न करने के लिए, और मेरा मानना ​​है (यह केवल व्यक्तिगत राय है) यह है कि वेक्टर कन्स्ट्रक्टर की जटिलता के संबंध में मानक में शब्द को संभवतः की आवश्यकता के अनुसार समायोजित किया जाना चाहिए, केवल उपयुक्त टी कन्स्ट्रक्टर, जहां उपयुक्त(यानी, एक निर्माता जो InputIterator::value_type (मूल्य या संभवतः निरंतर संदर्भ द्वारा), या टी प्रतिलिपि बनाकर कन्स्ट्रक्टर के रूप में परिभाषित किया जाना चाहिए, ructor टी InputIterator::value_type से एक अंतर्निहित रूपांतरण के बाद

23.2.4.1 [lib.vector.cons]/1

जटिलता: निर्माता टेम्पलेट वेक्टर (InputIterator पहले InputIterator पिछले) बनाता है केवल एन टी की कॉपी कन्स्ट्रक्टर को कॉल करें (जहां एन के बीच की दूरी पहले और आखिरी है) और कोई पुनर्विक्रय यदि पुनरावर्तक पहले और आखिरी आगे, बिडरेक्शनल या यादृच्छिक एक्सेस श्रेणियों के हैं। यह ऑर्डर एन टी और ऑर्डर लॉग एन प्रतिलिपि के प्रतिलिपि बनाने के लिए कॉल करता है यदि वे इनपुट इनपुटर हैं।

मुझे पता है कि व्यवहार कैसे वी.एस. संकलक जब दिया चाहते हैं:

struct T1; 
struct T2 { 
    operator T1(); 
}; 
struct T1 { 
    T1(T2 const &) { std::cout << "T1(T2)" << std::endl; } 
}; 
T2::operator T1() { 
    std::cout << "T2::operator T1" << std::endl; 
    return T1(*this); 
} 
int main() { 
    std::vector<T2> v2; 
    v2.push_back(T2()); 
    std::vector<T1> v1(v2.begin(), v2.end()); 
} 
जी के साथ

++ नतीजा यह है कि T2::operator T1 नहीं बुलाया जाता है, बल्कि v1 में तत्वों में तत्वों से सीधे निर्माण कर रहे हैं v2। मुझे लगता है कि वीएस के साथ संकलक T2::operator T1 का उपयोग v2 में प्रत्येक तत्व से टी 1 तत्व में कनवर्ट करने के लिए करेगा और फिर कॉपी कन्स्ट्रक्टर को कॉल करेगा। ऐसा क्या?

+0

वास्तव में, वीएस कंपाइलर के साथ अपने कोड को संकलित करने का प्रयास एक त्रुटि देता है (सी 2664): 'std :: आवंटक <_Ty> :: निर्माण': पैरामीटर 2 को 'टी 2' से 'कॉन्स्ट टी 1' 'में परिवर्तित नहीं कर सकता है [_Ty = T1 ] कारण: 'टी 2' से 'कॉन्स्ट टी 1' में परिवर्तित नहीं किया जा सकता है कोई उपयोगकर्ता परिभाषित-रूपांतरण ऑपरेटर उपलब्ध नहीं है जो इस रूपांतरण को निष्पादित कर सकता है, या ऑपरेटर को – user200783

+0

नहीं कहा जा सकता है मैंने अभी VS2010 बीटा के साथ परीक्षण किया है, और यह न केवल संकलित करता है लेकिन निष्पादित करता है उसी व्यवहार के साथ जी ++: 'टी 1 (टी 2 कॉन्स एंड) 'कन्स्ट्रक्टर बुलाया जाता है। –

1

यह सचमुच एक सवाल है कि एसटीएल लाइब्रेरी कैसे लागू की जाती है, एक भाषा विनिर्देश मुद्दा नहीं। भाषा की कल्पना में कुछ भी नहीं है जो इसे काम करने से रोक देगा, न ही ऐसा कुछ भी है जिसके लिए इसे काम करना चाहिए।

यदि एसटीएल :: वेक्टर कन्स्ट्रक्टर असाइनमेंट ऑपरेटर का उपयोग करके एक निहित रूपांतरण का प्रयास करने के लिए लिखा गया था, तो यह असफल हो जाएगा। यह अधिक संभावना है कि माइक्रोसॉफ्ट एसटीएल कार्यान्वयन एक कन्स्ट्रक्टर कॉल के माध्यम से प्रारंभिकरण के दौरान रिटर्न-वैल्यू ऑप्टिमाइज़ेशन का उपयोग करता है, इस मामले में यह कोड ठीक काम करेगा।

यह ध्यान रखना महत्वपूर्ण है कि यह काम करने का एकमात्र कारण है क्योंकि stl :: वेक्टर कन्स्ट्रक्टर टेम्पलेट किया गया है, और केवल आवश्यकता यह है कि यह एक इनपुट_इटरेटर है, या अधिक सटीक रूप से यह इनपुट की सभी आवश्यक कार्यक्षमता का समर्थन करता है इटरेटर।

मैं यह भी इंगित करना चाहता हूं कि यह एक प्रमुख उदाहरण है कि क्रॉस-प्लेटफ़ॉर्म कोड लिखना अक्सर मुश्किल क्यों होता है। कभी-कभी आप उन मुद्दों के साथ समाप्त होते हैं जहां न तो संकलक भाषा मानक से विचलित हो जाता है, लेकिन कोड अभी भी पोर्टेबल नहीं है।

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