3 प्रमुख C ++ कंपाइलर्स में प्रोग्राम को अलग तरीके से संकलित किया जा रहा है। कौनसा सही हैं?


116

एक दिलचस्प अनुवर्ती (हालांकि बड़े व्यावहारिक महत्व का नहीं) के रूप में मेरे पिछले प्रश्न के लिए: C ++ हमें एक चर घोषित करते समय कोष्ठक में चर नाम को घेरने की अनुमति क्यों देता है?

मुझे पता चला कि इंजेक्टेड क्लास नेम फ़ीचर के साथ कोष्ठक में घोषणा के संयोजन से कंपाइलर व्यवहार के बारे में आश्चर्यजनक परिणाम सामने आ सकते हैं।

निम्नलिखित कार्यक्रम पर एक नज़र डालें:

#include <iostream>
struct B
{
};

struct C
{
  C (){ std::cout << "C" << '\n'; }
  C (B *) { std::cout << "C (B *)" << '\n';}
};

B *y = nullptr;
int main()
{
  C::C (y);
}
  1. जी ++ 4.9.2 के साथ संकलन मुझे निम्नलिखित संकलन त्रुटि देता है:

    main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
  2. यह MSVC2013 / 2015 और प्रिंट के साथ सफलतापूर्वक संकलित करता है C (B *)

  3. यह क्लैंग 3.5 और प्रिंट के साथ सफलतापूर्वक संकलित है C

इतना अनिवार्य प्रश्न कि कौन सा सही है? :)

(मैं दृढ़ता से क्लैंग संस्करण की ओर अग्रसर हुआ, हालांकि और msvc तरीका केवल तकनीकी रूप से इसके टाइप किए गए अजीब के साथ बदलते प्रकार के बाद परिवर्तनीय घोषित करने से रोकने के लिए)


3
C::C y;समझ में नहीं आता है, है ना? न तो करता है C::C (y); पहले मैं पर सोचा इसमें से अधिकांश-अप्रिय-पार्स एक उदाहरण था stackoverflow.com/questions/tagged/most-vexing-parse , लेकिन अब मुझे लगता है कि अर्थ तीनों compilers सिर्फ अपरिभाषित व्यवहार है "ठीक है।"
डेल विल्सन

4
# 3 क्लैंग निश्चित रूप से गलत है, # 2 msvc बहुत अधिक अनुमत है और # 1 g ++ सही है ((मुझे लगता है)

8
C::Cएक प्रकार का नाम नहीं है यह एक फ़ंक्शन का नाम देता है, इसलिए GCC सही imo है।
गलिक


जवाबों:


91

GCC सही है, कम से कम C ++ 11 लुकअप नियमों के अनुसार। ३.४.३.१ [class.qual] / २ निर्दिष्ट करता है कि, यदि नेस्टेड नेम स्पेसियर वर्ग के नाम के समान है, तो यह कंस्ट्रक्टर को इंजेक्ट किए गए क्लास के नाम को नहीं दर्शाता है। यह उदाहरण देता है:

B::A ba;           // object of type A
A::A a;            // error, A::A is not a type name
struct A::A a2;    // object of type A

यह समारोह शैली डाली एक अस्थायी बनाने अभिव्यक्ति के रूप में MSVC misinterprets यह कैसा दिखता Cसाथ yएक निर्माता पैरामीटर के रूप में; और क्लैंग इसे एक yप्रकार की चर की घोषणा के रूप में गलत व्याख्या करता है C


2
हां, 3.4.3.1/2 कुंजी है। बहुत बढ़िया!
ऑर्बिट

यह कहता है "एक लुकअप में जिसमें फ़ंक्शन नामों को अनदेखा नहीं किया जाता है"। यह मुझे लगता है कि दिए गए उदाहरणों में, विशेष रूप से A::A a;, फ़ंक्शन नामों को अनदेखा किया जाना चाहिए - या नहीं?
कोलंबो

1
N4296 में नंबरिंग द्वारा जाना, कुंजी वास्तव में 3.4.3.1/2.1 है: "यदि नेस्टेड-नेम-स्पेसियर के बाद निर्दिष्ट नाम, जब सी में देखा जाता है, तो सी का इंजेक्शन-क्लास-नाम है [...] नाम को सी। के निर्माता का नाम माना जाता है। माइक का सारांश थोड़ा अधिक सरलीकृत है, हालांकि - उदाहरण के लिए, वर्ग के अंदर वर्ग-नाम का एक प्रकार का नाम एक नेस्टेड नाम निर्दिष्ट करेगा जो वर्ग नाम से अलग अभी भी वर्ग नाम को संदर्भित करता है, इसलिए यह अभी भी संदर्भित होगा। ctor।
जेरी कॉफिन

2
@Mgetz: इस सवाल से: "यह MSVC2013 / 2015 और प्रिंट के साथ सफलतापूर्वक संकलित है C (B *)"
ऑर्बिट

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

16

G ++ सही है क्योंकि यह एक त्रुटि देता है। क्योंकि newऑपरेटर के बिना ऐसे प्रारूप में सीधे निर्माता को नहीं बुलाया जा सकता है । और यद्यपि आपका कोड कॉल करता है C::C, यह एक कंस्ट्रक्टर कॉल की तरह दिखता है। हालाँकि, C ++ 11 मानक 3.4.3.1 के अनुसार, यह एक कानूनी फ़ंक्शन कॉल या एक प्रकार का नाम नहीं है ( माइक सेमोर का उत्तर देखें )।

क्लैंग गलत है क्योंकि यह सही फ़ंक्शन को भी नहीं बुलाता है।

MSVC कुछ उचित है, लेकिन फिर भी यह मानक का पालन नहीं करता है।


2
newऑपरेटर क्या बदलता है?
नील कर्क

1
@ नीलकेरिक: बहुत से लोग, जो सोचते हैं कि new B(1,2,3)किसी प्रकार का "डायरेक्ट कंस्ट्रक्टर कॉल" है (जो निश्चित रूप से, यह नहीं है) अस्थायी तात्कालिकता B(1,2,3)या घोषणा से अलग है B b(1,2,3)
ऑर्बिट

@LightningRacisinObrit आप कैसे वर्णन करेंगे new B(1,2,3)?
user2030677

1
@ user2030677: कीवर्ड new, एक प्रकार का नाम और एक कंस्ट्रक्टर तर्क सूची का उपयोग करके एक नई-अभिव्यक्ति । यह अभी भी "डायरेक्ट कंस्ट्रक्टर कॉल" नहीं है।
लाइटवेट रेस इन ऑर्बिट

"क्लैंग गलत है क्योंकि यह सही फ़ंक्शन को भी नहीं बुलाता है।": मुझे लगता है (क्योंकि घोषणाओं में कोष्ठक के बारे में ओपी की टिप्पणी) जो कि क्लैंग की व्याख्या C::C (y); करता है C::C y;, अर्थात टाइप सी के एक चर y का निषेध (इंजेक्शन प्रकार C का उपयोग करके: : C जबकि ग़लती से बढ़ती हुई भाषा विनिर्देश के 3.4.1,2 को अनदेखा कर रहा है जो C :: C को कंस्ट्रक्टर बनाता है)। जैसा कि आपको लगता है, imo के रूप में यह एक बहुत बड़ी त्रुटि नहीं है।
पीटर -
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.