क्यों "नाम एक्स का उपयोग कर;" वर्ग / संरचना स्तर के अंदर अनुमति नहीं है?


88
class C {
  using namespace std;  // error
};
namespace N {
  using namespace std; // ok
}
int main () {
  using namespace std; // ok
}

संपादित करें : इसके पीछे प्रेरणा जानना चाहते हैं।


1
@pst: C # में ऐसा कुछ नहीं है using namespace। C # कुछ समान अनुमति देता है, लेकिन केवल फ़ाइल स्कोप पर। C ++ का using namespaceआपको एक नाम स्थान दूसरे में शामिल करने की अनुमति देता है।
बिली ओनली जू

2
इस सवाल का डुप्लीकेट ?
महानवमी

@ZachSaw, मैं आपकी चिंता को समझता हूं। प्रासंगिकता के आधार पर Qn को बंद करने की कोशिश की है। चूँकि इस पोस्ट में मानक के लिए अधिक वस्तुनिष्ठ उत्तर और संदर्भ हैं, इसलिए मैंने इसे खुला रखा है। अतीत में, मेरे कई पुराने Qn नए Qn द्वारा बंद हो गए .. कभी-कभी मेरे द्वारा कभी-कभी दूसरों द्वारा। कृपया डायमंड मॉड्स को ध्वजांकित करें, क्या आपको यह महसूस करना चाहिए कि यह निर्णय उचित नहीं था। बुरा न मानो। :-)
iammilind

@iammilind टीबीएच की कम देखभाल नहीं कर सकता। एसओ इन दिनों गड़बड़ है। लेकिन एक पोस्ट को चिह्नित करना जो "मुझे ठीक से पता नहीं है" के साथ शुरू होता है क्योंकि उत्तर में वास्तव में "मानक के लिए अधिक उद्देश्य उत्तर और संदर्भ" होता है। Haha।
जच सॉ ने

@ZachSaw, मैं केवल स्वीकृत उत्तर के बारे में बात नहीं कर रहा था, लेकिन समग्र पोस्ट। हाँ, यह वस्तुनिष्ठ है लेकिन मानक उद्धरण इस उत्तर में निहित है । यह "मुझे नहीं पता" से शुरू होता है, क्योंकि मानक में भी, यह उचित नहीं है कि "नेमस्पेस का उपयोग करना" अंदर की अनुमति क्यों नहीं है class/struct। यह सिर्फ अनुमति नहीं है। लेकिन स्वीकृत जवाब इसे खारिज करने के लिए बहुत तार्किक तर्क पर चर्चा करता है। यानी कहां विचार करना है Hello::Worldऔर कहां विचार करना है World। आशा है कि संदेह को साफ करता है।
इमिलिंड

जवाबों:


35

मैं ठीक से नहीं जानता, लेकिन मेरा अनुमान है कि कक्षा के दायरे में इसकी अनुमति देने से भ्रम पैदा हो सकता है:

namespace Hello
{
    typedef int World;
}

class Blah
{
    using namespace Hello;
public:
    World DoSomething();
}

//Should this be just World or Hello::World ?
World Blah::DoSomething()
{
    //Is the using namespace valid in here?
}

चूंकि ऐसा करने का कोई स्पष्ट तरीका नहीं है, मानक केवल यह कहता है कि आप नहीं कर सकते।

अब, यह कारण कम भ्रमित है जब हम नेमस्पेस स्कैप्स बात कर रहे हैं:

namespace Hello
{
    typedef int World;
}

namespace Other
{
    using namespace Hello;
    World DoSomething();
}

//We are outside of any namespace, so we have to fully qualify everything. Therefore either of these are correct:

//Hello was imported into Other, so everything that was in Hello is also in Other. Therefore this is okay:
Other::World Other::DoSomething()
{
    //We're outside of a namespace; obviously the using namespace doesn't apply here.
    //EDIT: Apparently I was wrong about that... see comments. 
}

//The original type was Hello::World, so this is okay too.
Hello::World Other::DoSomething()
{
    //Ditto
}

namespace Other
{
    //namespace Hello has been imported into Other, and we are inside Other, so therefore we never need to qualify anything from Hello.
    //Therefore this is unambiguiously right
    World DoSomething()
    {
        //We're inside the namespace, obviously the using namespace does apply here.
    }
}

5
+1, मैंने इस कारण के बारे में सोचा, लेकिन फिर वही बात using namespace Hello;दूसरे के लिए namespaceभी लागू होती है (और externइसके अंदर फ़ंक्शन की घोषणा करते हुए )।
इमिलिंद

10
मुझे नहीं लगता कि यह भ्रामक है। C ++ अनुमान के बारे में नहीं है। यदि इसकी अनुमति थी, तो C ++ ISO समिति ने भाषा विनिर्देश में निर्दिष्ट किया होगा। तब आप इसके भ्रामक नहीं कहेंगे। अन्यथा कोई यह भी कह सकता है कि यह भ्रामक है: ideone.com/npOeD ... लेकिन फिर इस तरह के कोडिंग के लिए नियम निर्दिष्ट है।
नवाज

1
@ नवाज़: भाषा के अधिकांश उपयोगकर्ता। मैंने कभी नहीं कहा कि C ++ अनुमान के बारे में था। मैं यह कह रहा हूं कि जब कल्पना की जाती है, तो यह इस बात के साथ तैयार किया जाता है कि अधिकांश प्रोग्रामर किस व्यवहार की अपेक्षा करेंगे। और कागज पर नियम अक्सर भ्रमित करते हैं - मानक असंदिग्ध होने का प्रयास करते हैं लेकिन यह हमेशा सफल नहीं होता है।
बिली ओनली जू

6
पहले उदाहरण पर, यह होना चाहिए: Hello::World Blah::DoSomething()या Blah::World Blah::DoSomething()(यदि इसे अनुमति दी गई थी), तो सदस्य प्रकार की परिभाषा का वापसी प्रकार भाषा में वर्ग के दायरे में नहीं माना जाता है, इसलिए इसे योग्य होना चाहिए। जगह की वैध उदाहरण पर विचार करें usingएक साथ typedef Hello::World World;वर्ग दायरे में। इसलिए वहां कोई आश्चर्य नहीं होना चाहिए।
डेविड रॉड्रिग्ज - 7:13 पर drieas

2
अगर इसकी अनुमति दी गई थी, तो मेरा मानना ​​है कि इसे एक लेक्सिकल स्कोप के स्तर पर लागू किया जाएगा। मुझे लगता है कि यह "स्पष्ट" समाधान है जिसका वस्तुतः कोई लाभ नहीं है।
थॉमस एडिंग 19

18

क्योंकि C ++ मानक स्पष्ट रूप से इसे मना करता है। C ++ 03 C7.3.4 से [namespace.udir]:

उपयोग-निर्देश :
    नेमस्पेस का उपयोग :: ऑप्ट  नेस्टेड-नेम-स्पेसियर ऑप्ट  नेमस्पेस-नाम ;

एक प्रयोग-निर्देश वर्ग के दायरे में प्रकट नहीं होगा, लेकिन नाम स्थान के दायरे या ब्लॉक दायरे में दिखाई दे सकता है। [नोट: एक प्रयोग-निर्देश में एक नाम-स्थान की तलाश करते समय, केवल नामस्थान नामों पर विचार किया जाता है, 3.4.6 देखें। ]

C ++ मानक इसे क्यों मना करता है? मुझे नहीं पता, आईएसओ समिति के एक सदस्य से पूछें जिसने भाषा मानक को मंजूरी दी थी।


45
फिर भी एक और तकनीकी रूप से सही लेकिन बेकार जवाब; सबसे बुरा प्रकार। 1) सिर्फ कमेटी से ज्यादा लोग इसका जवाब जानते हैं। 2) समिति के सदस्य SO 3 में भाग लेते हैं) यदि आपको उत्तर नहीं पता (प्रश्न की भावना को देखते हुए) तो इसका उत्तर क्यों दिया गया?
१०:३६ पर कैटस्कुल

5
@ कैटस्कुल: यह बेकार जवाब नहीं है। यह जानना बहुत उपयोगी है कि मानक इसे स्पष्ट रूप से संबोधित करता है और इसे मना करता है। यह भी विडंबना है कि सबसे अधिक उत्कीर्ण उत्तर "मुझे ठीक से पता नहीं है" से शुरू होता है। इसके अलावा, "मानक इसे मना करता है" जैसा कि "इसकी अनुमति नहीं है क्योंकि संकलक इसे अनुमति नहीं देता है", क्योंकि बाद वाला मामला अनुवर्ती प्रश्नों का उत्तर नहीं देगा जैसे: क्या यह मेरे संकलक के साथ एक समस्या है? संकलक मानक-अनुरूप नहीं है? क्या यह कुछ अन्य चीजों का साइड इफेक्ट है, जिनके बारे में मुझे जानकारी नहीं है? आदि
एंटोनोन

9

मेरा मानना ​​है कि तर्क यह है कि यह संभवतः भ्रामक होगा। वर्तमान में, क्लास स्तर के पहचानकर्ता को संसाधित करते समय, लुकअप पहले वर्ग के दायरे में और फिर एनक्लोजिंग नेमस्पेस में खोज करेगा। using namespaceक्लास स्तर पर अनुमति देने से लुकअप कैसे किया जाता है, इस पर कुछ दुष्प्रभाव होंगे। विशेष रूप से, इसे उस विशेष वर्ग के दायरे की जाँच करने और संलग्न नामस्थान की जाँच करने के बीच कभी-कभी करना होगा। वह है: 1) वर्ग स्तर और प्रयुक्त नाम स्थान स्तर लुकअप का विलय, 2) वर्ग के दायरे के बाद उपयोग किए गए नाम स्थान की खोज करना लेकिन किसी भी अन्य वर्ग गुंजाइश से पहले, 3) संलग्न नामस्थान से ठीक पहले इस्तेमाल किए गए नामस्थान को देखें। 4) लुकअप एन्क्लेपिंग नामस्थान के साथ विलय हो गया।

  1. यह एक बड़ा अंतर है, जहां श्रेणी स्तर पर एक पहचानकर्ता होता होगा शैडो enclosing नाम स्थान में किसी भी पहचानकर्ता है, लेकिन यह नहीं होता शैडो एक प्रयोग किया जाता नाम स्थान। यह प्रभाव अजीब होगा, एक अलग नामस्थान में और एक ही नाम स्थान से एक वर्ग से इस्तेमाल किए गए नाम स्थान तक पहुंच अलग होगी:

namespace A {
   void foo() {}
   struct B {
      struct foo {};
      void f() {
         foo();      // value initialize a A::B::foo object (current behavior)
      }
   };
}
struct C {
   using namespace A;
   struct foo {};
   void f() {
      foo();         // call A::foo
   }
};
  1. इस वर्ग के दायरे के बाद लुकअप। यह बेस क्लास के सदस्यों को छाया देने का अजीब प्रभाव होगा। वर्तमान लुकअप क्लास और नेमस्पेस स्तर के लुकअप को मिक्स नहीं करता है, और क्लास लुकअप करते समय यह एनक्लोजिंग नेमस्पेस पर विचार करने से पहले बेस क्लासेस के लिए सभी तरह से जाएगा । यह व्यवहार आश्चर्यजनक होगा कि यह नामस्थान को समान स्तर पर एन्क्लोजिंग नेमस्पेस पर विचार नहीं करेगा। फिर से, उपयोग किए जाने वाले नाम स्थान को एन्क्लोज़िंग नामस्थान पर प्राथमिकता दी जाएगी।

namespace A {
   void foo() {}
}
void bar() {}
struct base {
   void foo();
   void bar();
};
struct test : base {
   using namespace A;
   void f() {
      foo();           // A::foo()
      bar();           // base::bar()
   }
};
  1. एनक्लोजिंग नेमस्पेस से पहले लुकअप। इस दृष्टिकोण के साथ समस्या फिर से है कि यह कई लोगों के लिए आश्चर्य की बात होगी। विचार करें कि नाम स्थान एक अलग अनुवाद इकाई में परिभाषित किया गया है, ताकि निम्नलिखित कोड को एक साथ नहीं देखा जा सके:

namespace A {
   void foo( int ) { std::cout << "int"; }
}
void foo( double ) { std::cout << "double"; }
struct test {
   using namespace A;
   void f() {
      foo( 5.0 );          // would print "int" if A is checked *before* the
                           // enclosing namespace
   }
};
  1. संलग्न नामस्थान के साथ मर्ज करें। इसका ठीक वही प्रभाव होगा जो usingनेमस्पेस स्तर पर घोषणा को लागू करने का होता है। यह उस पर कोई नया मूल्य नहीं जोड़ेगा, लेकिन दूसरी ओर संकलक कार्यान्वयनकर्ताओं के लिए जटिल खोज होगी। Namespace आइडेंटिफायर लुकअप अब स्वतंत्र है जहां से कोड में लुकअप ट्रिगर है। जब किसी वर्ग के अंदर, यदि लुकअप को पहचानकर्ता को क्लास स्कोप पर नहीं मिलता है तो वह वापस नेमस्पेस लुकअप में आ जाएगा, लेकिन यह वही नेमस्पेस लुकअप है जिसका उपयोग फंक्शन डेफिनिशन में किया जाता है, नए स्टेट को बनाए रखने की कोई आवश्यकता नहीं है। जब usingघोषणा नाम स्थान स्तर पर पाया जाता है, की सामग्री का इस्तेमाल किया नाम स्थान रहे लाया के लिए कि नेम स्पेस में सभी नाम स्थान को शामिल लुकअप। अगरusing namespace वर्ग के स्तर पर अनुमति दी गई थी, जहाँ पर लुकअप ट्रिगर किया गया था, उसके आधार पर सटीक समान नामस्थान के नामस्थान लुकअप के लिए अलग-अलग परिणाम होंगे, और यह बिना किसी अतिरिक्त मान के लुकअप के कार्यान्वयन को और अधिक जटिल बना देगा।

वैसे भी, मेरी सिफारिश घोषणा को नियोजित करने के लिए नहीं है using namespace। यह सभी नाम स्थान की सामग्री को ध्यान में रखे बिना कोड को सरल बनाता है।


1
मैं सहमत हूँ कि निहित विषमताओं को बनाने के लिए उपयोग करता है। लेकिन कुछ पुस्तकालय इस तथ्य के इर्द-गिर्द तैयार हो सकते हैं कि वे usingमौजूद हैं। जानबूझकर गहरी नेस्टेड लंबे नामस्थानों में चीजों की घोषणा करके। glmजब ग्राहक उपयोग करता है तो सुविधाओं को सक्रिय / प्रस्तुत करने के लिए एग करता है और कई तरकीबों का उपयोग करता है using
v.oddou

एसटीएल में भी सही using namespace std::placeholders। cf en.cppreference.com/w/cpp/utility/functional/bind
v.oddou

@ v.oddou:namespace ph = std::placeholders;
डेविड रॉड्रिग्ज -

1

यह शायद खुलेपन बनाम बंद होने के कारण अस्वीकृत है

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

कक्षाओं में नामस्थान आयात करने से इस तरह के मजेदार मामले सामने आएंगे:

namespace Foo {}

struct Bar { using namespace Foo; };

namespace Foo {
using Baz = int; // I've just extended `Bar` with a type alias!
void baz(); // I've just extended `Bar` with what looks like a static function!
// etc.
}

0

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

namespace Hello
{
    typedef int World;
}
// surround the class (where we want to use namespace Hello)
// by auxiliary namespace (but don't use anonymous namespaces in h-files)
namespace Blah_namesp {
using namespace Hello;

class Blah
{
public:
    World DoSomething1();
    World DoSomething2();
    World DoSomething3();
};

World Blah::DoSomething1()
{
}

} // namespace Blah_namesp

// "extract" class from auxiliary namespace
using Blah_namesp::Blah;

Hello::World Blah::DoSomething2()
{
}
auto Blah::DoSomething3() -> World
{
}

क्या आप कृपया कुछ स्पष्टीकरण जोड़ सकते हैं?
किशन भरदा

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