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

nri*_*lin 14 c++ namespaces using-directives language-lawyer c++11

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

// C.h
namespace NS {

class C {
    void f();
};

}
Run Code Online (Sandbox Code Playgroud)

并在实现文件中:

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

using namespace NS;
void C::f() {
  //...
}
Run Code Online (Sandbox Code Playgroud)

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

Tem*_*Rex 15

是的,语法确实合法,但不,你的函数确实存在于命名空间NS中.您看到的代码实际上等同于

namespace NS { void C::f() { /* ... } }
Run Code Online (Sandbox Code Playgroud)

或者

void NS::C::f() { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

这可能比你习惯的更类似.

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

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

7在声明命名空间成员的声明中,声明者成员是qualified-id,假定命名空间成员的qualified-id的形式为nested-name-specifier unqualified-id,则unqualified-id应命名为由nested-name-specifier或该命名空间的内联命名空间集(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
Run Code Online (Sandbox Code Playgroud)

-end example] 但是,在这样的命名空间成员声明中,嵌套名称说明符可能依赖于using-directives来隐式提供嵌套名称说明符的初始部分.[例如:

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)
Run Code Online (Sandbox Code Playgroud)

- 末端的例子]

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