मैं दोहरे कॉलनों का उपयोग करते हुए नाम स्थान में एक वर्ग को आगे-घोषित क्यों नहीं कर सकता?


164
class Namespace::Class;

मुझे ऐसा क्यों करना पडेगा?:

namespace Namespace {
    class Class;
}

VC ++ 8.0 का उपयोग करके, संकलक समस्याएँ:

त्रुटि C2653: 'नाम स्थान': एक वर्ग या नाम स्थान का नाम नहीं है

मुझे लगता है कि समस्या यह है कि संकलक यह नहीं बता सकता है कि Namespaceएक वर्ग या एक नाम स्थान है? लेकिन यह मामला क्यों है क्योंकि यह सिर्फ एक आगे की घोषणा है?

क्या किसी नामस्थान में परिभाषित वर्ग को अग्रेषित-घोषित करने का एक और तरीका है? उपर्युक्त वाक्य-विन्यास ऐसा महसूस करता है कि मैं नामस्थान को "पुनः खोल" रहा हूँ और इसकी परिभाषा का विस्तार कर रहा हूँ। यदि Classवास्तव में परिभाषित नहीं किया गया तो क्या होगा Namespace? क्या यह किसी बिंदु पर एक त्रुटि होगी?


44
मुझे यहां सभी उत्तरों से असहमत होने दें, और कहें कि यह भाषा का केवल एक डिज़ाइन बग है। वे बेहतर सोच सकते थे।
पावेल रेड्ज़विलोव्स्की

यह C ++ में अवैध क्यों है (जो व्यक्तिपरक है) की एक चर्चा की ओर बढ़ रहा है, और यह तर्कपूर्ण लग रहा है। मतदान बंद।
डेविड थोरले

7
कैसे संकलक पता चला है कि में माना जाता है कि एक नाम स्थान पहचानकर्ता के बजाय एक वर्ग के नाम है? A::BA
डेविड आर ट्रिब्बल

@STingRaySC: चर्चा व्यक्तिपरक है कि इसमें स्पष्ट जवाब नहीं है कि C ++ ऐसा क्यों करता है, इसलिए हम अनुमान लगा रहे हैं। (प्रश्न एक बन्दूक का सवाल है, जिसमें कुछ ऐसे प्रश्न होते हैं, जिनका उद्देश्य उत्तर होता है, जिनका उत्तर पहले ही दिया जा चुका है।) उस बिंदु पर, मैं तर्क के निशान के प्रति संवेदनशील हो जाता हूं, और पावेल के साथ आपका समझौता यह है कि यह C ++ का मिसफिट है। मुझे इस बात से कोई समस्या नहीं है कि यह Namespaceएक वर्ग या नाम स्थान क्यों है। सिंटैक्स पर भाषा की लौ युद्ध शुरू करने की संभावना के संकेत के पास कहीं भी नहीं मिलता है।
डेविड थॉर्नले

जवाबों:


85

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

और आप वास्तव में नई संस्थाओं की घोषणा करने के लिए नामस्थान "फिर से खोलना" कर रहे हैं । यदि Classबाद में कक्षा को विभिन्न नामस्थानों के सदस्य के रूप में परिभाषित किया जाता है - यह पूरी तरह से अलग वर्ग है जिसका आपके द्वारा यहां घोषित किए गए से कोई लेना-देना नहीं है।

एक बार जब आप पूर्व घोषित वर्ग को परिभाषित करने के बिंदु पर पहुंच जाते हैं , तो आपको फिर से नामस्थान को "फिर से खोलने" की आवश्यकता नहीं होती है। आप इसे वैश्विक नामस्थान (या किसी भी नामस्थान को घेरने वाले Namespace) के रूप में परिभाषित कर सकते हैं

class Namespace::Class {
  /* whatever */
};

चूंकि आप एक ऐसी इकाई का उल्लेख कर रहे हैं जो पहले से ही नामस्थान में घोषित की जा चुकी है Namespace, आप योग्य नाम का उपयोग कर सकते हैं Namespace::Class


10
@STingRaySC: एक नेस्टेड क्लास को फॉरवर्ड-डिक्लेयर करने का एकमात्र तरीका डिक्लेरेशन को एनक्लोजिंग क्लास की परिभाषा के अंदर रखना है । और एनक्लोजिंग क्लास की परिभाषा से पहले नेस्टेड क्लास को फॉरवर्ड-डिक्लेयर करने का कोई तरीका नहीं है।
चींटी

@STingRaySC: एक नेस्टेड वर्ग को घोषित किया जा सकता है - मेरा उत्तर देखें।
जॉन डिब्लिंग

8
@ जॉन डिब्लिंग: नेस्टेड क्लास एक अन्य वर्ग के अंदर घोषित एक वर्ग है। एक नेमस्पेस के अंदर तुरंत घोषित एक वर्ग एक नेस्टेड वर्ग नहीं है। आपके उत्तर में सेन्स्टेड कक्षाओं के बारे में कुछ भी नहीं है।
चींटी

198

आपको सही उत्तर मिल रहे हैं, मुझे बस फिर से प्रयास करने दें:

class Namespace::Class;

मुझे ऐसा क्यों करना पडेगा?

आपको यह करना होगा क्योंकि शब्द Namespace::Classसंकलक को बता रहा है:

... ठीक है, संकलक। नाम नाम स्थान का नाम स्थान खोजें, और उस वर्ग के नाम के वर्ग को देखें।

लेकिन संकलक को पता नहीं है कि आप किस बारे में बात कर रहे हैं क्योंकि यह किसी भी नामस्थान को नहीं जानता है Namespace। यहां तक ​​कि अगर कोई नाम स्थान भी होता है Namespace, जैसे:

namespace Namespace
{
};

class Namespace::Class;

यह अभी भी काम नहीं करेगा, क्योंकि आप उस नाम स्थान के बाहर से किसी नाम स्थान के भीतर एक वर्ग घोषित नहीं कर सकते। आपको नामस्थान में होना है।

तो, आप वास्तव में एक नाम स्थान के भीतर एक वर्ग घोषित कर सकते हैं। बस यह करें:

namespace Namespace
{
    class Class;
};

39
अन्य सभी उत्तर मुझे भ्रमित कर रहे थे लेकिन यह "आप उस नामस्थान के बाहर से किसी नाम स्थान के भीतर एक वर्ग की घोषणा नहीं कर सकते। आपको नामस्थान में होना होगा।" याद करने के लिए बहुत मददगार संकेत था।
द्वादशी

22

मुझे लगता है कि यह उसी कारण से है जब आप नेस्टेड नेमस्पेस को इस तरह से घोषित नहीं कर सकते:

namespace Company::Communications::Sockets {
}

और आपको यह करना होगा:

namespace Company {
  namespace Communications {
    namespace Sockets {
    }
  }
}

1
यह वास्तव में यह समझाने वाला उत्तर नहीं है कि आप ऐसा क्यों नहीं कर सकते।
StarPilot

6
यह एक उत्तर है जिसने मेरे समय की बड़ी राशि बचाई है
कादिर एर्डेम डेमीर

17
C ++ 17 इसे जोड़ता है।
रपरॉलिन

यहाँ आप जानते हैं कि सभी नामस्थान हैं। लेकिन क्लास कंपनी के साथ :: संचार :: सॉकेट आप नहीं जानते कि क्या संचार एक नामस्थान या एक वर्ग है (जहां सॉकेट नेस्टेड क्लास है)।
लोथर

12

यह स्पष्ट नहीं होगा कि आगे घोषित चर वास्तव में क्या है। आगे की घोषणा class Namespace::Class;का मतलब हो सकता है

namespace Namespace {
  class Class;
}

या

class Namespace {
public:
  class Class;
};


6
मुझे लगता है कि यह सबसे अच्छे उत्तरों में से एक है, क्योंकि यह जवाब देता है कि यह आसानी से संकलक द्वारा निर्धारित नहीं किया जा सकता है।
देवोलस

1

इसे रोकने में शामिल तर्क के बारे में बहुत सारे उत्कृष्ट उत्तर हैं। मैं केवल बोरिंग मानक प्रदान करना चाहता हूं ताकि विशेष रूप से निषिद्ध हो। यह C ++ 17 (n4659) के लिए सही है।

प्रश्न में पैराग्राफ है [class.name] / 2 :

केवल एक घोषणा जिसमें वर्ग-प्रमुख पहचानकर्ता शामिल हैं ; वर्तमान क्षेत्र में या तो नाम का पुनर्वितरण है या वर्ग नाम के रूप में पहचानकर्ता की आगे की घोषणा। यह वर्ग नाम को वर्तमान दायरे में पेश करता है।

उपरोक्त परिभाषित करता है कि आगे की घोषणा (या एक वर्ग के पुनर्वितरण) का गठन क्या है। मूलतः, यह से एक होना चाहिए class identifier;, struct identifier;या union identifier;जहां पहचानकर्ता में आम शाब्दिक परिभाषा है [lex.name] :

identifier:
  identifier-nondigit
  identifier identifier-nondigit
  identifier digit
identifier-nondigit:
  nondigit
  universal-character-name
nondigit: one of
  a b c d e f g h i j k l m
  n o p q r s t u v w x y z
  A B C D E F G H I J K L M
  N O P Q R S T U V W X Y Z _
digit: one of
  0 1 2 3 4 5 6 7 8 9

सामान्य योजना के उत्पादन से [a-zA-Z_][a-zA-Z0-9_]*हम सभी परिचित हैं। जैसा कि आप देख सकते हैं, यह class foo::bar;एक मान्य आगे की घोषणा होने से रोकता है, क्योंकि foo::barएक पहचानकर्ता नहीं है। यह पूरी तरह से योग्य नाम है, कुछ अलग है।

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