2015-01-19 9 views
8

हाल ही में मैं एक समस्या में भाग गया जो किसी भी तरह (लेकिन केवल किसी भी तरह) मुझे समझ में आता है। यह एकल (!) कन्स्ट्रक्टर तर्क की घोषणा के रूप में एक अस्थायी के निर्माण की व्याख्या करने पर आधारित है। कृपया नीचे दिए गए न्यूनतम उदाहरण पर एक नज़र डालें।फ़ंक्शन कॉल में अस्थायी निर्माण का घोषणा घोषणा के रूप में किया गया है

#include <iostream> 

class Foo0{ 
public: 
    Foo0(int a){}; 
    void doStuff() {std::cout<<"maap"<<std::endl;}; 
}; 

class Foo1{ 
public: 
    Foo1(int a){}; 
    void doStuff() {std::cout<<"maap"<<std::endl;}; 
}; 

class Foo2{ 
public: 
    Foo2(int a){}; 
    void doStuff() {std::cout<<"maap"<<std::endl;}; 
}; 

class Bar{ 
public: 
    Bar(Foo0 foo0, Foo1 foo1, Foo2 foo2){}; 
}; 

int main() { 
    int x = 1; 

    Bar bar0(Foo0(x), Foo1(x), Foo2(x)); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’; conflicting declaration ‘Foo2 x’ previous declaration as ‘Foo0 x’ 
    Bar bar1(Foo0{x}, Foo1(x), Foo2(x)); // Works WTF 
    Bar bar2(Foo0(x), Foo1{x}, Foo2(x)); // Works WTF 
    Bar bar3(Foo0(x), Foo1(x), Foo2{x}); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’ 
    Bar bar4(Foo0{x}, Foo1{x}, Foo2{x}); // Works totally makes sens to me 

    x.doStuff(); //Dose not work. This makes sens to me. But in the context its curious though. 
} 

मैं पहले से ही पढ़ा है कि जैसे भाव:

Foo(a); 

व्याख्या कर रहे हैं (एक मानक निर्माता है तो) एक की घोषणा के रूप में। यह समझ में आता है और यह पूरी तरह से ठीक है, क्योंकि आप निर्माण को स्पष्ट बनाने के लिए {}-ब्रैकेट का उपयोग कर सकते हैं। लेकिन मुझे समझ में नहीं आता है:

  1. बार0 के निर्माण में कोई समस्या क्यों है? सभी Foo के पास मानक कन्स्ट्रक्टर नहीं है। इसलिए की घोषणा के रूप में Foo0(x) जैसे कुछ की व्याख्या करने का अर्थ नहीं है।

  2. bar1 और bar2 का निर्माण क्यों काम करता है? यह मेरे लिए स्पष्ट है कि bar4 का निर्माण काम करता है, क्योंकि मैं सभी अस्थायी Foo एस के लिए {} -बैकेट का उपयोग करता हूं, इस प्रकार मैं जो चाहता हूं उसके बारे में स्पष्ट हूं।

  3. bar3 के निर्माण क्यों असफल हो यह {} Foo रों का केवल एक ही साथ -brackets उपयोग करने के लिए समस्या का समाधान करने के लिए ... केवल आवश्यक है करता है?

  4. इसके अलावा, एक्स को किसी भी बार का निर्माण करने से पहले घोषित किया जाता है। संकलक इस बारे में शिकायत क्यों नहीं करता?

अंतिम प्रश्न उदाहरण कोड की मेरी अंतिम पंक्ति से संबंधित है। लंबी कहानी छोटी: संकलक क्या सोचता है कि मैं उसे करना चाहता हूं और मुझे छाया की उपस्थिति कहां से याद आती है?

पीएस: यदि यह ब्याज की बात है - मैं जीसीसी -4.9.2 का उपयोग करता हूं।
पीपीएस: मैंने bar के कन्स्ट्रक्टर के साथ तर्क के रूप में तीन Foo0 एस के साथ ऐसा करने की कोशिश की। यहाँ वही कहानी। लेकिन त्रुटि विवादित घोषणा के बारे में कुछ भी नहीं कहती है, लेकिन x के पुनर्वितरण के बारे में कुछ भी नहीं कहती है।

+1

बस इतना ही आपको पता है, 'बार 0' एक समारोह की घोषणा है जो तीन 'फू' लेता है और 'फू' देता है, यह स्वयं 'फू' ऑब्जेक्ट नहीं है। साथ ही, तथ्य यह है कि 'bar3' की घोषणा काम नहीं करती है, जो भी संकलक आप उपयोग कर रहे हैं उसमें एक बग है। उस रेखा को काम करना चाहिए क्योंकि यह [clang] में है (http://coliru.stacked-crooked.com/a/d5f8305eff385830)। – 0x499602D2

+0

@ 0x499602D2 g ++ 4.8.1 –

+0

में मेरे लिए बग किया गया बस सही होने के लिए: 'bar0' एक फ़ंक्शन की घोषणा है जो तीन' Foo 'लेता है और' बार 'देता है। – sedriel

उत्तर

10

नियम यह है कि यदि घोषणा में फ़ंक्शन घोषणा का सिंटैक्स होता है तो यह एक होता है; अन्यथा यह एक परिवर्तनीय घोषणा है। इसके आश्चर्यजनक उदाहरणों को कभी-कभी कहा जाता है।

Bar bar0(Foo0(x), Foo1(x), Foo2(x)); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’; conflicting declaration ‘Foo2 x’ previous declaration as ‘Foo0 x’ 

यह एक समारोह घोषणा है: bar0 नाम है, Bar वापसी प्रकार है, और पैरामीटर प्रकार Foo0, Foo1 और Foo2 हैं। पैरामीटर नाम सभी x हैं जो अवैध हैं - फ़ंक्शन पैरामीटर के नाम अलग-अलग होना चाहिए। यदि आप xxx से xyz त्रुटि दूर हो जाती है)।

Bar bar1(Foo0{x}, Foo1(x), Foo2(x)); // Works WTF 
Bar bar2(Foo0(x), Foo1{x}, Foo2(x)); // Works WTF 
Bar bar4(Foo0{x}, Foo1{x}, Foo2{x}); // Works totally makes sens to me 

ये लाइनें और वस्तुओं bar1 बनाने के लिए, bar2, और प्रकार Bar की bar4। उन्हें फ़ंक्शन घोषणाओं के रूप में पार्स नहीं किया जा सकता है क्योंकि { } नोटेशन फ़ंक्शन घोषणा में मान्य वाक्यविन्यास नहीं है।

इसलिए, Foo0{x} आदि अभिव्यक्तियां हैं जो Bar के निर्माता को तर्क प्रदान करती हैं। Foo0{x} और Foo0(x) शुरुआती x के साथ अस्थायी प्रकार Foo0 घोषित करने के बराबर तरीके हैं।

Bar bar3(Foo0(x), Foo1(x), Foo2{x}); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’ 

मुझे लगता है कि यह एक कंपाइलर बग है; भाग Foo2{x} का अर्थ है कि यह लाइन फ़ंक्शन घोषणा नहीं हो सकती है; और यह एक चर bar3 की वैध घोषणा की तरह दिखता है।

x.doStuff(); //Dose not work. This makes sens to me. But in the context its curious 

x एक int है; इसमें कोई तरीका नहीं है।

+0

बार0 कानूनी कार्य घोषणा कैसे है? उस संदर्भ में 'टाइप (नाम)' का अर्थ क्या है? क्या यह केवल बाध्यकारी/समूह है, जैसे 'int (* foo) '- तो' टाइप (नाम)' 'टाइप नाम 'जैसा ही है? मैं वास्तव में कभी-कभी सी ++ पसंद करना शुरू कर रहा था। – JasonN

+0

@ जेसनएन [यहां देखें] (http://stackoverflow.com/questions/21624880/how-does-this-declaration-invoke-the-most-vexing-parse) एक अच्छी व्याख्या के लिए –

+0

धन्यवाद। जटिल पार्स की उत्कृष्टता। '-वेक्सिंग-पार्स' मजाकिया है। एक ही समय में दुखी – JasonN

2

1) इस उदाहरण में Foo0 (x) को फ़ंक्शन बार 0 के पैरामीटर के रूप में माना जाता है। यहां, इससे कोई फर्क नहीं पड़ता कि उसके पास मानक कन्स्ट्रक्टर है या नहीं। यह स्थानीय परिवर्तनीय घोषणा और प्रारंभिक नहीं है, लेकिन फ़ंक्शन घोषणा में केवल पैरामीटर घोषणा है।

2) मेरा अनुमान है कि इसमें पार्सिंग के साथ कुछ करना है, लेकिन अगर मैं गलत हूं तो कोई मुझे सही करता है .. उदाहरण बार 1 और बार 2 काम, क्योंकि संकलक जानता है कि बार 1 और बार 2 स्थानीय परिवर्तनीय घोषणाएं हैं (और नहीं कार्य घोषणाएं) जैसे ही यह {} की पहली घटना को देखता है। {} से पहले प्रकट होने वाले ये पहली घटनाएं फ़ंक्शन के पैरामीटर के रूप में दो बार घोषित की जाती हैं।

3) बार 3 का निर्माण विफल रहता है, क्योंकि संकलक पहले मानता है कि बार 3 एक समारोह घोषणा है। फ़ंक्शन घोषणा में तीन पैरामीटर होते हैं, जिन्हें सभी नामित x होते हैं। जाहिर है, यह सही नहीं है।

4) फ़ंक्शन घोषणा में एक्स पैरामीटर के लिए सिर्फ एक नाम है। यह आपके द्वारा घोषित पूर्णांक एक्स की तुलना में एक अलग दायरे में है।

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