खोज…


परिचय

कई पुस्तकालयों का उपयोग करते समय नाम टकराव को रोकने के लिए उपयोग किया जाता है, एक नाम स्थान कार्य, वर्ग, प्रकार, आदि के लिए एक घोषणात्मक उपसर्ग है।

वाक्य - विन्यास

  • नाम स्थान पहचानकर्ता ( ऑप्ट ) { घोषणा-seq }
  • इनलाइन नेमस्पेस आइडेंटिफ़ायर ( ऑप्ट ) { घोषणापत्र-seq } / * चूंकि C ++ 11 * /
  • इनलाइन ( ऑप्ट ) नेमस्पेस विशेषता-विशेष-सीक पहचानकर्ता ( ऑप्ट ) { घोषणा-सीक्यू } / * C ++ 17 * / के बाद से
  • नामस्थान संलग्नक-नाम स्थान-विवरण :: पहचानकर्ता { घोषणा-seq } / * चूंकि C ++ 17 * /
  • नाम स्थान पहचानकर्ता = योग्य-नाम स्थान-निर्दिष्ट ;
  • नेमस्पेस नेस्टेड-नेम-स्पेसियर ( ऑप्ट ) नेमस्पेस-नेम ;
  • विशेषता-विनिर्देशक-सेक नाम स्थान नेस्ट-नाम-विनिर्देशक (वैकल्पिक) नाम स्थान-नाम का उपयोग; / * C ++ 11 * / के बाद से

टिप्पणियों

संदर्भ के आधार पर कीवर्ड namespace के तीन अलग-अलग अर्थ हैं:

  1. जब वैकल्पिक नाम और घोषणाओं के ब्रेस-एनक्लोज्ड अनुक्रम के बाद, यह एक नया नामस्थान परिभाषित करता है या उन घोषणाओं के साथ एक मौजूदा नाम स्थान का विस्तार करता है । यदि नाम छोड़ दिया जाता है, तो नामस्थान एक अनाम नामस्थान है

  2. जब एक नाम और एक समान चिह्न के बाद, यह एक नाम स्थान उपनाम घोषित करता है।

  3. जब किसी नेमस्पेस नाम using और अनुसरण किया जाता है, तो यह एक निर्देशन का उपयोग करता है , जो दिए गए नेमस्पेस में नामों को अयोग्य नाम के लुकअप द्वारा पाया जा सकता है (लेकिन मौजूदा दायरे में उन नामों को फिर से सूचीबद्ध नहीं करता है)। कक्षा के दायरे में एक प्रयोग-निर्देश नहीं हो सकता है।

using namespace std; हतोत्साहित किया जाता है। क्यों? क्योंकि namespace std बहुत बड़ा है! इसका मतलब है कि एक उच्च संभावना है कि नाम टकराएंगे:

//Really bad!
using namespace std;

//Calculates p^e and outputs it to std::cout
void pow(double p, double e) { /*...*/ }

//Calls pow
pow(5.0, 2.0); //Error! There is already a pow function in namespace std with the same signature,
               //so the call is ambiguous

नाम स्थान क्या हैं?

C ++ नामस्थान, C ++ संस्थाओं (फ़ंक्शन, वर्ग, चर) का एक संग्रह है, जिनके नाम नाम के नाम से उपसर्ग हैं। किसी नामस्थान के भीतर कोड लिखते समय, उस नामस्थान से संबंधित नामांकित संस्थाओं को नामस्थान नाम के साथ उपसर्ग करने की आवश्यकता नहीं है, लेकिन इसके बाहर की संस्थाओं को पूरी तरह से योग्य नाम का उपयोग करना चाहिए। पूरी तरह से योग्य नाम का प्रारूप <namespace>::<entity> । उदाहरण:

namespace Example
{
  const int test = 5;

  const int test2 = test + 12; //Works within `Example` namespace
}

const int test3 = test + 3; //Fails; `test` not found outside of namespace.

const int test3 = Example::test + 3; //Works; fully qualified name used.

नाम-पत्र संबंधित परिभाषाओं को एक साथ समूहीकृत करने के लिए उपयोगी हैं। एक शॉपिंग मॉल की सादृश्य लें। आम तौर पर एक शॉपिंग मॉल को कई दुकानों में विभाजित किया जाता है, प्रत्येक दुकान एक विशिष्ट श्रेणी से आइटम बेचती है। एक दुकान इलेक्ट्रॉनिक्स बेच सकती है, जबकि दूसरी दुकान जूते बेच सकती है। स्टोर प्रकारों में ये तार्किक पृथक्करण दुकानदारों को उन वस्तुओं को खोजने में मदद करते हैं जिन्हें वे ढूंढ रहे हैं। Namespaces दुकानदारों की तरह c ++ प्रोग्रामर की मदद करते हैं, जो उन्हें तार्किक तरीके से व्यवस्थित करके उन कार्यों, कक्षाओं, और चर की तलाश करते हैं। उदाहरण:

namespace Electronics
{
    int TotalStock;
    class Headphones
    {
        // Description of a Headphone (color, brand, model number, etc.)
    };
    class Television
    {
        // Description of a Television (color, brand, model number, etc.)
    };
}

namespace Shoes
{
    int TotalStock;
    class Sandal
    {
        // Description of a Sandal (color, brand, model number, etc.)
    };
    class Slipper
    {
        // Description of a Slipper (color, brand, model number, etc.)
    };
}

एक एकल नामस्थान पूर्वनिर्धारित है, जो वैश्विक नामस्थान है जिसका कोई नाम नहीं है, लेकिन :: द्वारा निरूपित किया जा सकता है। उदाहरण:

void bar() {
    // defined in global namespace
}
namespace foo {
    void bar() {
        // defined in namespace foo
    }
    void barbar() {
        bar();   // calls foo::bar()
        ::bar(); // calls bar() defined in global namespace
    }
}

नाम स्थान बनाना

नाम स्थान बनाना वास्तव में आसान है:

//Creates namespace foo
namespace Foo
{
    //Declares function bar in namespace foo
    void bar() {}
}

bar को कॉल करने के लिए, आपको पहले नाम स्थान निर्दिष्ट करना होगा, उसके बाद गुंजाइश रिज़ॉल्यूशन ऑपरेटर ::

Foo::bar();

उदाहरण के लिए, एक नाम स्थान बनाने की अनुमति है:

namespace A
{
    namespace B
    {
        namespace C
        {
            void bar() {}
        }
    }
}
सी ++ 17

उपरोक्त कोड निम्नलिखित के लिए सरल किया जा सकता है:

namespace A::B::C
{
    void bar() {}
}

नाम स्थान का विस्तार

namespace की एक उपयोगी विशेषता यह है कि आप उनका विस्तार कर सकते हैं (सदस्यों को इसमें जोड़ सकते हैं)।

namespace Foo
{
    void bar() {}
}

//some other stuff

namespace Foo
{
    void bar2() {}
}

निर्देशन का उपयोग करना

'का उपयोग कर' कीवर्ड के तीन स्वाद हैं। कीवर्ड 'नेमस्पेस' के साथ मिलकर आप 'निर्देश का उपयोग करते हुए' लिखते हैं:

यदि आप नामस्थान Foo में हर सामान के सामने Foo:: लिखना नहीं चाहते हैं, तो आप using namespace Foo; उपयोग using namespace Foo; सकते हैं using namespace Foo; Foo बाहर हर एक चीज को आयात करने के लिए।

namespace Foo
{
    void bar() {}
    void baz() {}
}

//Have to use Foo::bar()
Foo::bar();

//Import Foo
using namespace Foo;
bar(); //OK
baz(); //OK

संपूर्ण नामस्थान के बजाय किसी नाम स्थान में चयनित निकाय आयात करना भी संभव है:

using Foo::bar;
bar(); //OK, was specifically imported
baz(); // Not OK, was not imported

चेतावनी का एक शब्द: हेडर फ़ाइलों में using namespace एस using namespace ज्यादातर मामलों में खराब शैली के रूप में देखा जाता है। यदि ऐसा किया जाता है, तो प्रत्येक फ़ाइल में नाम स्थान आयात किया जाता है जिसमें शीर्षलेख शामिल होता है। चूंकि किसी नेमस्पेस का "संयुक्त राष्ट्र" using करने का कोई तरीका नहीं है, इससे नेमस्पेस प्रदूषण हो सकता है (वैश्विक नामस्थान में अधिक या अप्रत्याशित प्रतीकों) या, बदतर, संघर्ष। इस उदाहरण को समस्या के चित्रण के लिए देखें:

/***** foo.h *****/
namespace Foo
{
    class C;
}

/***** bar.h *****/
namespace Bar
{
    class C;
}

/***** baz.h *****/
#include "foo.h"
using namespace Foo;

/***** main.cpp *****/
#include "bar.h"
#include "baz.h"

using namespace Bar;
C c; // error: Ambiguity between Bar::C and Foo::C

कक्षा के दायरे में एक प्रयोग-निर्देश नहीं हो सकता है।

तर्क निर्भर लुकअप

एक स्पष्ट नामस्थान योग्यताधारी के बिना किसी फ़ंक्शन को कॉल करते समय, कंपाइलर एक नाम स्थान के भीतर एक फ़ंक्शन को कॉल करने का विकल्प चुन सकता है यदि उस फ़ंक्शन के पैरामीटर प्रकार में से एक भी उस नाम स्थान में है। इसे "तर्क पर निर्भर लुकअप" या ADL कहा जाता है:

namespace Test
{
  int call(int i);

  class SomeClass {...};

  int call_too(const SomeClass &data);
}

call(5); //Fails. Not a qualified function name.

Test::SomeClass data;

call_too(data); //Succeeds

call विफल हो जाता है क्योंकि इसका कोई भी पैरामीटर प्रकार Test नाम स्थान से नहीं आता है। call_too काम करता है क्योंकि SomeClass Test सदस्य है और इसलिए यह ADL नियमों के लिए योग्य है।

ADL कब नहीं होता है

ADL तब नहीं होता है जब सामान्य अयोग्य लुकअप एक क्लास सदस्य पाता है, एक फ़ंक्शन जिसे ब्लॉक स्कोप पर घोषित किया गया है, या ऐसा कुछ जो फ़ंक्शन प्रकार का नहीं है। उदाहरण के लिए:

void foo();
namespace N {
    struct X {};
    void foo(X ) { std::cout << '1'; }
    void qux(X ) { std::cout << '2'; }
}

struct C {
    void foo() {}
    void bar() {
        foo(N::X{}); // error: ADL is disabled and C::foo() takes no arguments
    }
};

void bar() {
    extern void foo(); // redeclares ::foo
    foo(N::X{});       // error: ADL is disabled and ::foo() doesn't take any arguments
}

int qux;

void baz() {
    qux(N::X{}); // error: variable declaration disables ADL for "qux"
}

इनलाइन नेमस्पेस

सी ++ 11

inline namespace में एन्ग्लोसिंग नेमस्पेस में इनबिल्ड नेमस्पेस की सामग्री शामिल है, इसलिए

namespace Outer
{
    inline namespace Inner
    {
        void foo();
    }
}

के बराबर है

namespace Outer
{

    namespace Inner
    {
        void foo();
    }

    using Inner::foo;
}

लेकिन से तत्व Outer::Inner:: और में जुड़े लोगों के Outer:: समान हैं।

तो निम्नलिखित बराबर है

Outer::foo();
Outer::Inner::foo();

using namespace Inner; विकल्प using namespace Inner; टेम्प्लेट स्पेशलाइजेशन के रूप में कुछ मुश्किल हिस्सों के लिए समान नहीं होगा:

के लिये

#include <outer.h> // See below

class MyCustomType;
namespace Outer
{
    template <>
    void foo<MyCustomType>() { std::cout << "Specialization"; }
}
  • इनलाइन नेमस्पेस Outer::foo के विशेषज्ञता की अनुमति देता है

    // outer.h
    // include guard omitted for simplification
    
    namespace Outer
    {
        inline namespace Inner
        {
            template <typename T>
            void foo() { std::cout << "Generic"; }
        }
    }
    
  • जबकि using namespace Outer::foo के विशेषज्ञता की अनुमति नहीं देते हैं

    // outer.h
    // include guard omitted for simplification
    
    namespace Outer
    {
        namespace Inner
        {
            template <typename T>
            void foo() { std::cout << "Generic"; }
        }
        using namespace Inner;
        // Specialization of `Outer::foo` is not possible
        // it should be `Outer::Inner::foo`.
    }
    

इनलाइन नाम स्थान साथ रहना करने के लिए कई संस्करण और को दोषी अनुमति देने के लिए एक रास्ता है inline एक

namespace MyNamespace
{
    // Inline the last version
    inline namespace Version2
    {
        void foo(); // New version
        void bar();
    }

    namespace Version1 // The old one
    {
        void foo();
    }

}

और उपयोग के साथ

MyNamespace::Version1::foo(); // old version
MyNamespace::Version2::foo(); // new version
MyNamespace::foo();           // default version : MyNamespace::Version1::foo();

अनाम अनाम नाम

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

namespace {
    int foo = 42;
}

foo केवल अनुवाद इकाई में दिखाई देता है जिसमें यह दिखाई देता है।

शीर्ष लेख फ़ाइलों में अनाम नामस्थानों का उपयोग न करने की अनुशंसा की जाती है क्योंकि यह इसमें शामिल हर अनुवाद इकाई के लिए सामग्री का एक संस्करण देता है। यह विशेष रूप से महत्वपूर्ण है यदि आप गैर-कास्ट ग्लोबल्स को परिभाषित करते हैं।

// foo.h
namespace {
    std::string globalString;
}

// 1.cpp
#include "foo.h" //< Generates unnamed_namespace{1.cpp}::globalString ...

globalString = "Initialize";

// 2.cpp
#include "foo.h" //< Generates unnamed_namespace{2.cpp}::globalString ...

std::cout << globalString; //< Will always print the empty string

कॉम्पैक्ट नेस्टेड नामस्थान

सी ++ 17
namespace a {
  namespace b {
    template<class T>
    struct qualifies : std::false_type {};
  }
}

namespace other {
  struct bob {};
}

namespace a::b {
  template<>
  struct qualifies<::other::bob> : std::true_type {};
}

आप एक चरण में a और b दोनों नामस्थानों के साथ एक नाम दर्ज कर सकते हैं namespace a::b C ++ 17 में शुरू होने वाला namespace a::b

एक लंबे नामस्थान का नामकरण

इसका उपयोग आमतौर पर लंबे नामस्थान संदर्भों को पुनर्नामित या छोटा करने के लिए किया जाता है, जैसे कि पुस्तकालय के घटकों के संदर्भ में।

namespace boost
{
    namespace multiprecision
    {
        class Number ...
    }
}

namespace Name1 = boost::multiprecision;


//    Both Type declarations are equivalent
boost::multiprecision::Number X   //    Writing the full namespace path, longer
Name1::Number Y                   //    using the name alias, shorter

उपनाम की घोषणा की गुंजाइश

बयानों का उपयोग करने से पहले उपनाम की घोषणा प्रभावित होती है

namespace boost
{
    namespace multiprecision
    {
        class Number ...
    }
}


using namespace boost;

//   Both Namespace are equivalent 
namespace Name1 = boost::multiprecision;
namespace Name2 = multiprecision;

हालाँकि, यह आसान है कि आप किस नामस्थान पर भ्रमित हो रहे हैं जब आपके पास कुछ ऐसा हो:

namespace boost
{
    namespace multiprecision
    {
        class Number ...
    }
}

namespace numeric
{
    namespace multiprecision
    {
        class Number ...
    }
}

using namespace numeric;
using namespace boost;

//    Not recommended as 
//    its not explicitly clear whether Name1 refers to
//    numeric::multiprecision or boost::multiprecision
namespace Name1 = multiprecision;

//    For clarity, its recommended to use absolute paths
//    instead
namespace Name2 = numeric::multiprecision;
namespace Name3 = boost::multiprecision;

नेमस्पेस एलियास

namespace आइडेंटिफ़ायर = सिंटैक्स का उपयोग करके एक नेमस्पेस को एक अन्य नाम दिया जा सकता है ( यानी, उसी नाम का दूसरा नाम)। अलियास नामस्थान के सदस्यों को उपनाम के नाम के साथ अर्हता प्राप्त करके पहुँचा जा सकता है। निम्न उदाहरण में, नेस्टेड नामस्थान AReallyLongName::AnotherReallyLongName टाइप करने के लिए असुविधाजनक है, इसलिए फ़ंक्शन qux स्थानीय रूप से एक उपनाम N घोषित करता है। उस नाम स्थान के सदस्यों को केवल N:: का उपयोग करके पहुँचा जा सकता है।

namespace AReallyLongName {
    namespace AnotherReallyLongName {
        int foo();
        int bar();
        void baz(int x, int y);
    }
}
void qux() {
    namespace N = AReallyLongName::AnotherReallyLongName;
    N::baz(N::foo(), N::bar());
}


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow