c++ सी++ में घोषणाएं




pointers const (2)

जो मैंने समझा है, सी ++ में घोषणाएं / प्रारंभिकरण 'आधार प्रकार' के साथ बयान हैं, इसके बाद घोषणाकर्ताओं की अल्पविराम से अलग सूची के बाद।

निम्नलिखित घोषणाओं पर विचार करें:

int i = 0, *const p = &i; // Legal, the so-called base type is 'int'.
                          // i is an int while p is a const pointer to an int.

int j = 0, const c = 2;   // Error: C++ requires a type specifier for all declarations.
                          // Intention was to declare j as an int and c an as const int.

int *const p1 = nullptr, i1 = 0; // p1 is a const pointer to an int while i1 is just an int.

int const j1 = 0, c1 = 2;   // Both j1 and c1 are const int.

क्या आधार आधार या कंपाउंड प्रकार है?

उपर्युक्त दूसरी घोषणा में त्रुटि से, यह एक मूल प्रकार प्रतीत होता है। यदि ऐसा है, तो पहली घोषणा के बारे में क्या?

दूसरे शब्दों में, यदि पहला कथन कानूनी है, तो दूसरा क्यों नहीं है? इसके अलावा, व्यवहार तीसरे और चौथे वक्तव्य के बीच क्यों भिन्न होता है?


यह simple-declaration * के हिस्से के रूप में [dcl.dcl] और [dcl.decl] में निर्दिष्ट है और पीआरटी-घोषणाकर्ता में शाखाओं के बीच मतभेदों के लिए उबाल जाता है:

declaration-seq:
    declaration

declaration:
    block-declaration

block-declaration:
    simple-declaration

simple-declaration:
    decl-specifier-seqopt init-declarator-listopt ;
----

decl-specifier-seq:
    decl-specifier decl-specifier-seq    

decl-specifier:    
    type-specifier                               ← mentioned in your error

type-specifier:
    trailing-type-specifier

trailing-type-specifier:
    simple-type-specifier
    cv-qualifier
----

init-declarator-list:
   init-declarator
   init-declarator-list , init-declarator

init-declarator:
   declarator initializeropt

declarator:
    ptr-declarator

ptr-declarator:                                 ← here is the "switch"
    noptr-declarator
    ptr-operator ptr-declarator

ptr-operator:                                   ← allows const
    *  cv-qualifier-seq opt

cv-qualifier:
    const
    volatile

noptr-declarator:                               ← does not allow const
    declarator-id

declarator-id:
    id-expression

नियमों में महत्वपूर्ण कांटा ptr-declarator :

ptr-declarator:
    noptr-declarator
    ptr-operator ptr-declarator

अनिवार्य रूप से, आपके संदर्भ में noptr-declarator केवल एक id-expression । इसमें कोई cv-qualifier नहीं हो सकता है, लेकिन योग्य या अयोग्य आईडी हो सकती है। हालांकि, एक ptr-operator में एक cv-qualifier हो सकता है।

यह इंगित करता है कि आपका पहला कथन पूरी तरह मान्य है, क्योंकि आपका दूसरा init-declarator

 *const p = &i;

इस मामले में ptr-operator * const ptr-operator साथ फॉर्म ptr-operator ptr-declarator ptr-declarator का एक ptr-declarator ptr-operator ptr-declarator और ptr-declarator एक अयोग्य पहचानकर्ता है।

आपका दूसरा कथन कानूनी नहीं है क्योंकि यह वैध ptr-operator :

 const c = 2

एक ptr-operator * , & , && या नेस्टेड नाम विनिर्देशक के साथ * शुरू होना चाहिए। चूंकि noptr-declarator const c उन टोकन में से किसी एक के साथ शुरू नहीं होता है, इसलिए हम noptr-declarator const c को noptr-declarator रूप में noptr-declarator , जो यहां noptr-declarator अनुमति नहीं देता है।

इसके अलावा, व्यवहार तीसरे और चौथे बयान के बीच क्यों भिन्न है?

क्योंकि int type-specifier , और * init-declarator का हिस्सा है,

*const p1

निरंतर सूचक घोषित करता है।

हालांकि, int const , हमारे पास दो decl-specifier , int (एक simple-type-specifier ) और const (एक cv-qualifier ) का एक decl-specifier-seq है, trailing-type-specifier । इसलिए दोनों एक घोषणा विनिर्देशक बनाते हैं।

* नोट: मैंने उन सभी विकल्पों को छोड़ दिया है जिन्हें यहां लागू नहीं किया जा सकता है और कुछ नियमों को सरल बनाया जा सकता है। अधिक जानकारी के लिए खंड 7 "घोषणाएं" और सी ++ 11 ( n3337 ) की धारा 8 " n3337 " का संदर्भ लें।


एक जटिल जवाब के साथ अच्छा सवाल है। वास्तव में इसे समझने के लिए, आपको सी ++ घोषणाओं की आंतरिक संरचना को पूरी तरह से समझने की आवश्यकता है।

(ध्यान दें कि इस जवाब में, मैं अतिसंवेदनशीलता को रोकने के लिए विशेषताओं के अस्तित्व को पूरी तरह से छोड़ दूंगा)।

एक घोषणा में दो घटक होते हैं: विनिर्देशकों का अनुक्रम , इसके बाद इनिट-घोषणाकर्ताओं की अल्पविराम से अलग सूची के बाद।

विनिर्देशक इस तरह की चीजें हैं:

  • भंडारण वर्ग विनिर्देशक (जैसे static , extern )
  • फ़ंक्शन विनिर्देशक (जैसे virtual , inline )
  • friend , typedef , constexpr
  • टाइप विनिर्देशक , जिनमें शामिल हैं:
    • सरल प्रकार विनिर्देशक (जैसे int , short )
    • सीवी-क्वालीफायर ( const , volatile )
    • अन्य चीजें (जैसे decltype )

घोषणा का दूसरा भाग अल्पविराम से अलग इनिट-घोषणाकर्ता हैं। प्रत्येक init-declarator में घोषणाकर्ताओं का अनुक्रम होता है , वैकल्पिक रूप से प्रारंभकर्ता द्वारा पीछा किया जाता है।

क्या घोषणाकर्ता हैं:

  • पहचानकर्ता (उदाहरण के लिए i int i; )
  • पॉइंटर-जैसे ऑपरेटर ( * , & , && , पॉइंटर-टू-सदस्य सिंटैक्स)
  • फ़ंक्शन पैरामीटर सिंटैक्स (उदाहरण के लिए (int, char) )
  • सरणी वाक्यविन्यास (उदाहरण के लिए [2][3] )
  • सीवी-क्वालीफायर , यदि ये एक सूचक घोषणाकर्ता का पालन करते हैं।

ध्यान दें कि घोषणा की संरचना सख्त है: पहले विनिर्देशक, फिर इन-घोषणाकर्ता (प्रत्येक घोषणाकर्ता वैकल्पिक रूप से प्रारंभकर्ता द्वारा पीछा किया जाता है)।

नियम यह है: विनिर्देशक पूरी घोषणा पर लागू होते हैं, जबकि घोषणाकर्ता केवल एक इन-घोषणाकर्ता (अल्पविराम से अलग सूची के एक तत्व के लिए) पर लागू होते हैं।

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

इसलिए, आपके द्वारा पोस्ट की गई चार घोषणाओं को संभालने के लिए:

1

int i = 0, *const p = &i;

निर्दिष्ट भाग में केवल एक विनिर्देशक होता है: int । यही वह हिस्सा है जो सभी घोषणाकर्ता लागू होंगे।

दो init-declarators हैं: i = 0 और * const p = &i

पहले व्यक्ति में एक घोषणाकर्ता, i , और प्रारंभिक = 0 । चूंकि कोई प्रकार-संशोधित घोषणाकर्ता नहीं है, इसलिए इस प्रकार के विनिर्देशकों द्वारा int का प्रकार दिया जाता है।

दूसरे init-declarator में तीन घोषणाकर्ता हैं: * , const , और p । और एक प्रारंभिक, = &i

घोषणाकर्ता * और const बेस प्रकार को "मूल प्रकार के निरंतर सूचक" के रूप में संशोधित करते हैं। विनिर्देशकों द्वारा दिया गया आधार प्रकार int , p के प्रकार के लिए " int लिए निरंतर सूचक" होगा।

2

int j = 0, const c = 2;

दोबारा, एक विनिर्देशक: int , और दो init-declarators: j = 0 और const c = 2

दूसरे init-declarator के लिए, const और c । जैसा कि मैंने उल्लेख किया है, व्याकरण केवल सीवी-क्वालीफायर को घोषणाकर्ताओं के रूप में अनुमति देता है यदि कोई सूचक शामिल है। यह मामला यहां नहीं है, इसलिए त्रुटि।

3

int *const p1 = nullptr, i1 = 0;

एक विनिर्देशक: int , दो init-declarators: * const p1 = nullptr और i1 = 0

पहले init-declarator के लिए, घोषणाकर्ता हैं: * , const , और p1 । हमने पहले से ही इस तरह के एक इन-घोषणाकर्ता (दूसरे मामले में 1 ) के साथ निपटाया है। यह निर्दिष्टकर्ता परिभाषित आधार प्रकार (जो अभी भी int ) में "आधार प्रकार के लिए स्थिर सूचक" जोड़ता है।

दूसरे init-declarator i1 = 0 , यह स्पष्ट है। कोई प्रकार संशोधन नहीं, निर्दिष्टकर्ताओं का उपयोग करें। तो i1 एक int बन जाता है।

4

int const j1 = 0, c1 = 2;

यहां, हमारे पास पिछले तीनों से मूल रूप से अलग स्थिति है। हमारे पास दो विनिर्देशक हैं: int और const । और फिर दो init-declarators, j1 = 0 और c1 = 2

इनमें से कोई भी इन-घोषणाकर्ताओं में उनमें से कोई भी प्रकार-संशोधित घोषणाकर्ता नहीं है, इसलिए वे दोनों विनिर्देशकों के प्रकार का उपयोग करते हैं, जो कि const int





declaration