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

我想知道它背后的动机。

4

6 回答 6

37

我不确切知道,但我的猜测是在类范围内允许这样做可能会导致混淆:

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.
    }
}
于 2011-06-13T05:09:46.667 回答
14

因为 C++ 标准明确禁止它。从 C++03 §7.3.4 [namespace.udir]:

使用指令:
    using namespace :: opt 嵌套名称说明符opt  namespace-name ;

using 指令不应出现在类范围内,但可以出现在命名空间范围或块范围内。[注意:在 using 指令中查找命名空间名称时,仅考虑命名空间名称,参见 3.4.6。]

为什么 C++ 标准禁止它?我不知道,请问批准语言标准的 ISO 委员会成员。

于 2011-06-13T05:05:48.583 回答
9

我相信理由是它可能会令人困惑。目前,在处理类级别标识符时,查找将首先在类范围内搜索,然后在封闭的命名空间中搜索。允许using namespaceat class 级别将对现在如何执行查找产生相当多的副作用。特别是,它必须在检查特定类范围和检查封闭命名空间之间的某个时间执行。即:1)合并类级别和使用的命名空间级别查找,2)在类范围之后但在任何其他类范围之前查找使用的命名空间,3)在封闭命名空间之前查找使用的命名空间。4) 查找与封闭的命名空间合并。

  1. 这将产生很大的不同,其中类级别的标识符将隐藏封闭命名空间中的任何标识符,但不会隐藏使用的命名空间。效果会很奇怪,因为从不同命名空间中的类和同一个命名空间访问使用的命名空间会有所不同:

.

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这与在命名空间级别应用声明具有完全相同的效果。它不会为此添加任何新值,但另一方面会使编译器实现者的查找变得复杂。命名空间标识符查找现在独立于代码中触发查找的位置。在类内部,如果查找在类范围内找不到标识符,它将回退到命名空间查找,但这与函数定义中使用的命名空间查找完全相同,无需维护新状态。当using在命名空间级别找到声明时,使用的命名空间的内容将带入命名空间,以便所有涉及该命名空间的查找。如果using namespace如果在类级别允许,则对于完全相同的命名空间的命名空间查找将有不同的结果,具体取决于触发查找的位置,这将使查找的实现更加复杂而没有额外的价值。

无论如何,我的建议是根本不使用该using namespace声明。它使代码更易于推理,而无需记住所有命名空间的内容。

于 2011-06-13T08:01:01.903 回答
3

我认为这是语言的缺陷。您可以使用以下解决方法。牢记此解决方法,很容易为更改语言的情况建议名称冲突解决规则。

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
{
}
于 2019-12-20T09:02:06.963 回答
2

由于开放性封闭性,这可能是不允许的。

  • 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.
}
于 2020-07-05T11:08:05.017 回答
-1

您不能using namespace在类内部使用,但您可以做的只是简单地使用#define,然后#undef在结构内部使用。它的行为方式与namespace a = b;

struct foo
{
#define new_namespace old_namespace
     
    void foo2()
    {
        new_namespace::do_something();
    }

#undef new_namespace 
};
于 2022-01-09T14:07:48.063 回答