可以在声明它们的命名空间之外定义类成员吗?

时间:2014-08-07 07:50:55

标签: c++ c++11 namespaces language-lawyer using-directives

有时候我会找到类似下面的代码(实际上有些类向导会创建这样的代码):

// C.h
namespace NS {

class C {
    void f();
};

}

并在实施文件中:

// C.cpp
#include "C.h"

using namespace NS;
void C::f() {
  //...
}

我尝试的所有编译器都接受这种代码(gcc,clang,msvc,compileonline.com)。让我感到不舒服的是using namespace NS;。从我的观点来看,C::f()存在于一个环境中,该环境对访问生命在命名空间NS中的对象具有不合格的访问权限。但是编译器的意见void C::f()存在于namespace NS中。正如我尝试的所有编译器分享这一观点一样,他们可能是正确的,但是在标准中这个观点的支持是什么?

1 个答案:

答案 0 :(得分:14)

是的,语法确实合法,但不,您的功能确实存在于名称空间NS 中。您看到的代码实际上等同于

namespace NS { void C::f() { /* ... } }

void NS::C::f() { /* ... */ }

可能与您习惯的类似。

由于using指令,您不仅可以在调用代码时省略NS部分,还可以在其定义中省略NS部分。标准有一个与您的代码匹配的示例(在粗体强调部分之后):

3.4.3.2命名空间成员[namespace.qual]

  

7在声明者成员的声明中,声明者身份   是一个限定id,给定命名空间的qualified-id   member的形式为nested-name-specifier unqualified-id   unqualified-id应命名由。指定的命名空间的成员   嵌套名称说明符或内联命名空间集的元素   该命名空间的(7.3.1)。 [例如:

namespace A {
  namespace B {
    void f1(int);
  }
  using namespace B;
}
void A::f1(int){ } // ill-formed, f1 is not a member of A
  

-end example] 但是,在这样的命名空间成员声明中,   嵌套名称说明符可以依赖于使用指令   提供嵌套名称说明符的初始部分。 [示例:

namespace A {
  namespace B {
    void f1(int);
  }
}

namespace C {
  namespace D {
    void f1(int);
  }
}

using namespace A;
using namespace C::D;
void B::f1(int){ } // OK, defines A::B::f1(int)
  

-end example]

因此,您可以省略嵌套名称说明符的初始部分,但不是任何中间部分