मूल्य आरंभीकरण पर मेरा प्रयास एक फ़ंक्शन घोषणा के रूप में व्याख्या किया गया है, और ए (ए) (क्यों) नहीं करता है; इसे हल करो?


158

ढेर सारी चीजों के बीच स्टैक ओवरफ्लो ने मुझे सिखाया है कि "सबसे डरावने तोते" के रूप में क्या जाना जाता है, जिसे शास्त्रीय रूप से एक लाइन के साथ प्रदर्शित किया जाता है जैसे कि

A a(B()); //declares a function

हालांकि, ज्यादातर के लिए, सहज रूप से एक aप्रकार की वस्तु की घोषणा प्रतीत होती है A, एक अस्थायी Bवस्तु को एक निर्माण पैरामीटर के रूप में लेते हुए , यह वास्तव में एक फ़ंक्शन की aवापसी की घोषणा है, एक फ़ंक्शन के Aलिए एक सूचक ले जाता है जो वापस लौटता है Bऔर स्वयं कोई पैरामीटर नहीं लेता है । इसी तरह रेखा

A a(); //declares a function

भी एक ही श्रेणी के अंतर्गत आता है, क्योंकि एक वस्तु के बजाय, यह एक समारोह घोषित करता है। अब, पहले मामले में, इस मुद्दे के लिए सामान्य वर्कअराउंड कोष्ठक / कोष्ठक के अतिरिक्त सेट को चारों ओर जोड़ना है B(), क्योंकि संकलक तब किसी वस्तु की घोषणा के रूप में इसकी व्याख्या करेगा।

A a((B())); //declares an object

हालांकि, दूसरे मामले में, एक ही करने से संकलन त्रुटि हो जाती है

A a(()); //compile error

मेरा सवाल है, क्यों? हां, मैं बहुत अच्छी तरह से जानता हूं कि सही 'वर्कअराउंड' इसे बदलने के लिए है A a;, लेकिन मैं यह जानने के लिए उत्सुक हूं कि यह क्या है कि अतिरिक्त ()पहले उदाहरण में कंपाइलर के लिए करता है जो फिर इसे लागू करने पर काम नहीं करता है दूसरा उदाहरण। क्या A a((B()));वर्कअराउंड मानक में लिखा गया एक विशिष्ट अपवाद है?


20
(B())बस एक C ++ अभिव्यक्ति है, और कुछ नहीं। यह किसी भी तरह का अपवाद नहीं है। एकमात्र अंतर जो यह बनाता है कि कोई तरीका नहीं है कि इसे संभवतः एक प्रकार के रूप में पार्स किया जा सकता है, और इसलिए यह नहीं है।
पावेल मिनेव

12
यह भी ध्यान दिया जाना चाहिए कि दूसरा मामला, A a();एक ही श्रेणी का नहीं है। के लिए संकलक , वहाँ यह पार्स करने के लिए किसी भी अलग तरह से कभी नहीं है: उस जगह पर एक प्रारंभकर्ता कभी नहीं, खाली कोष्ठकों के होते हैं तो यह हमेशा होता है एक समारोह घोषणा।
जोहान्स शाउब -

11
लिटब का उत्कृष्ट बिंदु एक सूक्ष्म अभी तक महत्वपूर्ण है और जोर देने लायक है - इस घोषणा में मौजूद अस्पष्टता का कारण 'ए (बी) ())' बी () 'के पार्सिंग में है -> यह दोनों एक अभिव्यक्ति हो सकती है और एक घोषणा और संकलक को expr पर 'पिक' घोषित करना होगा - इसलिए यदि B () एक घोषणा है, तो 'a' केवल एक func घोषना हो सकती है (एक चर घोषित नहीं)। यदि '()' को इनिशियलाइज़र होने की अनुमति दी गई थी तो 'A a ()' अस्पष्ट होगा - लेकिन expr बनाम डिक्लेयर नहीं, लेकिन var डिक्सेस बनाम func डिक्लेयर - किसी दूसरे पर एक डिक्लेरेशन पसंद करने का कोई नियम नहीं है - और (') 'यहाँ सिर्फ एक आरंभिक के रूप में अनुमति नहीं है - और अस्पष्टता नहीं बढ़ती है।
फैसल वली

6
A a();है का एक उदाहरण सबसे अप्रिय पार्स । यह बस एक फ़ंक्शन घोषणा है, ठीक उसी तरह जैसे सी। में है
पीट बेकर

2
"सही 'वर्कअराउंड' इसे बदलने के लिए है A a;" गलत है। यह आपको POD प्रकार का आरंभीकरण नहीं देगा। इंट्रस्टीलेशन लिखने के लिए A a{};
चीयर्स एंड हीथ। - अल्फ

जवाबों:


70

कोई प्रबुद्ध उत्तर नहीं है, यह सिर्फ इसलिए है क्योंकि इसे C ++ भाषा द्वारा मान्य सिंटैक्स के रूप में परिभाषित नहीं किया गया है ... इसलिए यह ऐसा है, भाषा की परिभाषा के अनुसार।

यदि आपके पास एक अभिव्यक्ति है तो यह मान्य है। उदाहरण के लिए:

 ((0));//compiles

और भी सरल: क्योंकि (x)एक वैध C ++ अभिव्यक्ति है, जबकि ()ऐसा नहीं है।

भाषाएं कैसे परिभाषित की जाती हैं और कंपाइलर कैसे काम करते हैं, इस बारे में अधिक जानने के लिए, आपको औपचारिक भाषा सिद्धांत या विशेष रूप से संदर्भ मुक्त व्याकरण (सीएफजी) और परिमित राज्य मशीनों जैसी संबंधित सामग्री के बारे में सीखना चाहिए । यदि आपकी रुचि इस बात में है कि विकिपीडिया पृष्ठ पर्याप्त नहीं होंगे, तो आपको एक पुस्तक प्राप्त करनी होगी।


45
और भी सरल: क्योंकि (x)एक वैध C ++ अभिव्यक्ति है, जबकि ()ऐसा नहीं है।
पावेल मिनेव

मैंने इस उत्तर को स्वीकार कर लिया है, इसके अलावा पावेल की मेरे प्रारंभिक प्रश्न पर टिप्पणी से मुझे बहुत मदद मिली
GRB


29

सी समारोह में घोषणाकर्ता

सबसे पहले, सी इन सी है, A a()फ़ंक्शन घोषणा है। उदाहरण के लिए, putcharनिम्नलिखित घोषणा है। आम तौर पर, ऐसी घोषणाओं को हेडर फ़ाइलों में संग्रहीत किया जाता है, हालांकि कुछ भी आपको मैन्युअल रूप से लिखने से रोकता है, यदि आप जानते हैं कि फ़ंक्शन की घोषणा कैसे दिखती है। तर्क नाम घोषणाओं में वैकल्पिक हैं, इसलिए मैंने इसे इस उदाहरण में छोड़ दिया।

int putchar(int);

यह आपको इस तरह कोड लिखने की अनुमति देता है।

int puts(const char *);
int main() {
    puts("Hello, world!");
}

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

#include <stdio.h>

int eighty_four() {
    return 84;
}

int output_result(int callback()) {
    printf("Returned: %d\n", callback());
    return 0;
}

int main() {
    return output_result(eighty_four);
}

जैसा कि मैंने उल्लेख किया है, सी हेडर फ़ाइलों में तर्क नामों को छोड़ने की अनुमति देता है, इसलिए output_resultहेडर फ़ाइल में ऐसा दिखेगा।

int output_result(int());

कंस्ट्रक्टर में एक तर्क

क्या आप उस एक को नहीं पहचानते? खैर, आपको याद दिला दूं।

A a(B());

हां, यह बिल्कुल वही फ़ंक्शन घोषणा है। Aहै int, aहै output_resultऔर Bहै int

आप आसानी से C ++ की नई विशेषताओं के साथ C के संघर्ष को नोटिस कर सकते हैं। सटीक होने के लिए, कन्स्ट्रक्टरों को वर्ग नाम और कोष्ठक के रूप में जाना जाता है, और वैकल्पिक घोषणा सिंटैक्स के ()बजाय =। डिज़ाइन के अनुसार, C ++ C कोड के साथ संगत होने की कोशिश करता है, और इसलिए इसे इस मामले से निपटना पड़ता है - भले ही व्यावहारिक रूप से किसी को परवाह न हो। इसलिए, पुराने C फीचर्स में नए C ++ फीचर्स को प्राथमिकता दी गई है। घोषणाओं के व्याकरण के साथ नए वाक्यविन्यास पर वापस जाने से पहले, नाम को फ़ंक्शन के रूप में मिलान करने की कोशिश करता है() यदि वह विफल हो जाता है।

यदि उन विशेषताओं में से एक मौजूद नहीं होगा, या एक अलग सिंटैक्स था (जैसे {}C ++ 11 में), तो यह समस्या एक तर्क के साथ सिंटैक्स के लिए कभी नहीं हुई होगी।

अब आप पूछ सकते हैं कि A a((B()))काम क्यों करता है। खैर, चलो output_resultबेकार कोष्ठक के साथ घोषणा करते हैं।

int output_result((int()));

यह काम नहीं करेगा। व्याकरण को चर को कोष्ठक में नहीं होने की आवश्यकता होती है।

<stdin>:1:19: error: expected declaration specifiers or ‘...’ before ‘(’ token

हालाँकि, C ++ यहाँ मानक अभिव्यक्ति की उम्मीद करता है। C ++ में, आप निम्न कोड लिख सकते हैं।

int value = int();

और निम्न कोड।

int value = ((((int()))));

C ++ कोष्ठकों के अंदर अभिव्यक्ति की उम्मीद है ... अच्छी तरह से ... अभिव्यक्ति, जैसा कि टाइप सी की उम्मीद है। कोष्ठक यहाँ कुछ भी मतलब नहीं है। हालांकि, बेकार कोष्ठकों को सम्मिलित करके, सी फ़ंक्शन घोषणा से मिलान नहीं किया जाता है, और नए सिंटैक्स को ठीक से मिलान किया जा सकता है (जो कि बस एक अभिव्यक्ति की उम्मीद करता है, जैसे 2 + 2)।

कंस्ट्रक्टर में अधिक तर्क

निश्चित रूप से एक तर्क अच्छा है, लेकिन दो के बारे में क्या? ऐसा नहीं है कि कंस्ट्रक्टरों के पास सिर्फ एक तर्क हो सकता है। अंतर्निहित कक्षाओं में से एक जो दो तर्क लेता हैstd::string

std::string hundred_dots(100, '.');

यह सब ठीक है और ठीक है (तकनीकी रूप से, यह सबसे अधिक डरावनी तोता होगा यदि इसे इस रूप में लिखा जाएगा std::string wat(int(), char()), लेकिन चलो ईमानदार होंगे - जो इसे लिखेंगे? लेकिन मान लें कि इस कोड में एक समस्या है। आप मान लेंगे कि आपको डालनी होगी। कोष्ठक में सब कुछ।

std::string hundred_dots((100, '.'));

ऐसा बिलकुल नहीं है।

<stdin>:2:36: error: invalid conversion from char to const char*’ [-fpermissive]
In file included from /usr/include/c++/4.8/string:53:0,
                 from <stdin>:1:
/usr/include/c++/4.8/bits/basic_string.tcc:212:5: error:   initializing argument 1 of std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ [-fpermissive]
     basic_string<_CharT, _Traits, _Alloc>::
     ^

मुझे यकीन नहीं है कि क्यों जी ++ में बदलने की कोशिश करता charहै const char *। किसी भी तरह से, निर्माता को केवल एक प्रकार के मूल्य के साथ बुलाया गया था char। कोई अधिभार नहीं है जिसके पास एक प्रकार का तर्क है char, इसलिए संकलक भ्रमित है। आप पूछ सकते हैं - तर्क टाइप चार का क्यों है?

(100, '.')

हाँ, ,यहाँ एक अल्पविराम ऑपरेटर है। अल्पविराम ऑपरेटर दो तर्क लेता है, और दाईं ओर तर्क देता है। यह वास्तव में उपयोगी नहीं है, लेकिन यह मेरे स्पष्टीकरण के लिए जाना जाने वाला कुछ है।

इसके बजाय, सबसे अधिक डरावने पार्स को हल करने के लिए, निम्न कोड की आवश्यकता है।

std::string hundred_dots((100), ('.'));

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

कंस्ट्रक्टर में शून्य तर्क

आपने eighty_fourमेरे स्पष्टीकरण में फ़ंक्शन को देखा होगा ।

int eighty_four();

जी हां, यह सबसे ज्यादा डरावने तोते से भी प्रभावित होता है। यह एक मान्य परिभाषा है, और यदि आपने हेडर फ़ाइलें (और आपको चाहिए) बनाई हैं, तो आपको सबसे अधिक संभावना है। कोष्ठक जोड़ना इसे ठीक नहीं करता है।

int eighty_four(());

ऐसा क्यों हैं? खैर, ()एक अभिव्यक्ति नहीं है। सी ++ में, आपको कोष्ठक के बीच एक अभिव्यक्ति डालनी होगी। आप auto value = ()C ++ में नहीं लिख सकते हैं , क्योंकि ()इसका मतलब कुछ भी नहीं है (और अगर किया भी है, जैसे कि खाली ट्यूपल (पायथन देखें), यह एक तर्क होगा, शून्य नहीं)। व्यावहारिक रूप से इसका मतलब है कि आप C ++ 11 के {}सिंटैक्स का उपयोग किए बिना शॉर्टहैंड सिंटैक्स का उपयोग नहीं कर सकते हैं , क्योंकि कोष्ठक में डालने के लिए कोई अभिव्यक्ति नहीं है, और फ़ंक्शन घोषणाओं के लिए सी व्याकरण हमेशा लागू होगा।


12

आप इसके बजाय कर सकते हैं

A a(());

उपयोग

A a=A();

32
'बेहतर समाधान' समतुल्य नहीं है। 0 के साथ int a = int();शुरू aहोता है, असिंचित int a;छोड़ देता है a। एक सही वर्कअराउंड A a = {};समुच्चय के लिए उपयोग करना है, A a;जब डिफ़ॉल्ट-आरंभीकरण आप क्या चाहते हैं, और A a = A();अन्य सभी मामलों में - या बस A a = A();लगातार उपयोग करें । C ++ 11 में, बस इस्तेमाल करेंA a {};
रिचर्ड स्मिथ

6

आपके उदाहरण में अंतरतम प्रतिमान एक अभिव्यक्ति होगी, और C ++ में व्याकरण expressionएक assignment-expressionया expressionएक अल्पविराम द्वारा अनुगमन करता है और दूसरा assignment-expression(परिशिष्ट A.4 - व्याकरण सारांश / अभिव्यक्तियाँ)।

व्याकरण आगे assignment-expressionकई अन्य प्रकार की अभिव्यक्तियों में से एक के रूप में परिभाषित करता है , जिनमें से कुछ भी (या केवल व्हाट्सएप) कुछ भी नहीं हो सकता है।

तो कारण तुम नहीं कर सकते हैं A a(()) है क्योंकि व्याकरण इसकी अनुमति नहीं देता है। हालाँकि, मैं इस बात का जवाब नहीं दे सकता कि C ++ को बनाने वाले लोगों ने किसी प्रकार के विशेष मामले के रूप में खाली पार्न्स के इस विशेष उपयोग की अनुमति क्यों नहीं दी - मुझे लगता है कि वे ऐसे विशेष मामले में नहीं डालते अगर वहाँ था एक उचित विकल्प।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.