为什么内部包含的名称空间不是私有的?

时间:2015-08-04 20:00:31

标签: c++ namespaces

或换句话说,为什么要允许这个编译?:

#include <iostream>
namespace N{
  using namespace std;
  string bar() { return "bar";}
  void foo() { cout<<"foo\n"<<bar()<<endl; }
}
int main(){
  N::foo();
  N::cout<<">why allow this??\n"; //Can't ::N:: keep `::std::` to itself?
}

为什么不让每个命名空间在内部解析其内部包含指令,只“导出”该命名空间中实际存在的内容?

使它像这样工作将消除在大多数地方使用命名空间块内的完全限定名称的需要,我不能想到这些缺点。

除了在实施者身上使事情变得更容易之外,这种行为是否有任何目的?

修改

事实证明,在当前命名空间(B)和包含的(using指令)命名空间(C)之间没有争用时,它至少在某种程度上是合理的 - 当前命名空间(B)总是获胜。然而,如果当前的命名空间(B)包含在别处(A)然后突然,突然,B和C开始竞争,这对于从未知道C的B的用户来说一定是奇怪的:

#include <iostream>

namespace C { 
  void method() { std::cout<<"C\n"; } 
  void cmethod() { std::cout<<"cmethod\n"; } 
}
namespace B { using namespace C; 
              void method() { std::cout<<"B\n"; } }

///^^Library
///>User code

namespace A { 
  using namespace B;
  void aMethod() {
    //method(); Error: 
    //conflict between B::method and C::method even though A doesn't even know about C
    B::method(); //Why do I need to write this when I just included B?

    cmethod();   //This simply leaks from C because of the u-directive
  }
}

int main() { A::aMethod(); }

3 个答案:

答案 0 :(得分:2)

据我所知,这个特征已由Bjarne Stroustrup本人提出的N0635明确引入。该提案中提到的第一个原因是为什么应该引入这个功能是因为他一再被要求做这项工作:&#34;

namespace A {
    int f();
}

using namespace A;

void g()
{
    ::f(); // call A::f
}
     

和这个

namespace A {
    int f();
}

namespace B {
    using namespace A;
}

void g()
{
    B::f(); // call A::f
}
     

根据现行规则,这不起作用,因为B::f表示&#34;看   对于在f&#34;中声明的B并且f未声明B

但该文件中提到了其他原因:

  

有人可能会说这种解释更接近B::f的方式   总是为基类B工作。一个好处是   简化库头,因为

namespace std {
    int printf(const char* ... );
    // ...
}

using namespace std;

int main()
{
    ::printf("Hello pedantic world\n");
}
     

现在可以工作了。这种放松是被接受的,我期待的   标准.h标题要更改为使用 using-directive s(as   最初的意图)而不是 using-declaration 。这样可以节省   数百行声明。

     

另外,如果有人

static void f(char);
void f(int);

void g()
{
    ::f(’a’);  // calls f(char)
}
     

并天真地将其翻译为

namespace { void f(char); }
void f(int);

void g()
{
    ::f(’a’);  // current rules: class f(int)
               // relaxed rules: calls f(char)
}
     

然后在现行规则下会有意义的变化,但是   不符合我建议的新规则。有些人担心   当前规则暗示的意义变化。

     

人们已经回应了这个提议,例如&#34; obvius,&#34;   &#34;这就是我的意思,&#34;和#34;我认为这就是它所做的。&#34;   我认为这是放松不会导致的指标   增加了教学问题,但可能会减少这些问题。

答案 1 :(得分:1)

实际上, The C ++ Programming Language (1986)的原始版本中不存在名称空间。稍后介绍它们,目的是管理元素的逻辑分组。从其他现有命名空间中组合新命名空间的能力是所需功能的一部分(参见Stroustrup当前版本的8.2.8节)。

标准就是这样,真正的问题是:在你自己的标准命名空间中使用std命名空间是Herb Sutter's recommendations的一个好习惯吗?这可能更安全:

// === For exposure in a header ====
namespace N{
  std::string bar();  // std:: because not sure std is used in the surrounding context 
  void foo(); 
}
// === For use in the implemenation ===
using namespace std;  // for the implementation 
namespace N {
  string bar() { return "bar";}  
  void foo() { cout<<"foo\n"<<bar()<<endl; }
}

当前的命名空间逻辑也有优势。例如,您可以管理库的不同版本,仍允许在过渡期间使用遗留部件,通过显式范围重新构建。

namespace my_super_lib {
    namespace my_super_lib_v1 {  // legacy API
        void super_f()  { std::cout<<"1"; } 
        void super_old() {}   // obsolete, 
    }
    namespace my_super_lib_v2 {   // new API
        void super_f(int a) { std::cout<<"2"; }
    }
    using namespace my_super_lib_v2; // use now the new API
    using my_super_lib_v1::super_old; // but still allow some legacy 
}; 

Stroutrup's FAQ显示了类似的示例,另外还有inline命名空间的明确案例。

答案 2 :(得分:0)

好吧,如果您不希望这种情况发生,请不要在using namespace std内执行namespace N或类似内容...

有时能够将某个命名空间中的某个东西“导出”到另一个命名空间中非常有用。想象一下,我有一套聪明的功能来执行flubbetiflap功能。为了这个目标,我在kerflunk命名空间中借用了一组函数,它提供了一些我想在我的功能中使用的非常有用的类型声明。所以我可以这样做:

namespace flubbetiflap
{
    using namespace kerflunk;
    ... all the good code what I wrote to do flubbetiflap goes here ... 
};

现在,我flubbetiflap的用户实际上并不需要知道我正在使用kerflunk进行实施。

当然,可能存在各种可能的解决方案,COULD可能会提出这样做​​。但我当然可以看到它是如何有用的。

显然,C ++委员会以外的任何人都不会真正了解正在进行的讨论,以确定这应该如何运作......