Class 在其命名空间之外定义的成员函数

Class member function defined outside its namespace

以下代码可与 godbolt 在线编译器资源管理器站点提供的最新 MSVC、GCC 和 CLang 完美编译。我想知道为什么:

namespace ns
{
    struct Test
    {
        void foo();
    };
}

using namespace ns;

// Alert! Member function defined outside its namespace!
void Test::foo()
{
}

int main()
{
    ns::Test   obj;
    obj.foo();
    return 0;
}

cppreference 声称,如果一个成员函数是在其 class 之外定义的,那么它必须在 class 的命名空间中定义。请参阅有关 member functions.

的 cppreference 页面的最顶部

但是,编译器仍然接受代码。所有三个独立的编译器都不太可能有相同的错误,对吧?那么,他们接受这样的代码背后有充分的理由吗?

using namespace ns;

5) using-directive: From the point of view of unqualified name lookup of any name after a using-directive and until the end of the scope in which it appears, every name from ns_name is visible as if it were declared in the nearest enclosing namespace which contains both the using-directive and ns_name.

这意味着在当前范围内 ns 可以省略,不去处理该命名空间内的某些内容。

当你写这段代码时:

using namespace std;
vector<string> vectorofstrings;

你不必写

std::vector<std::string> vectorofstrings;

class 的 namespace 是 class 的名称。所以如果你有:

namespace aNamespace{

class aClass{
    int aMember;
    void aFunction();
};

}

那么完全限定的查找是 ::aNamespace::aClass 并且函数必须定义为 void ::aNamespace::aClass::aFunction(){}

的一部分

引用 C++17 (n4659) 12.2.1 [class.mfct]/1:

A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition.

这意味着它必须在包含 class 的命名空间或该命名空间的任何父命名空间中定义。在您的情况下,它是在全局命名空间中定义的,它确实(间接)包含了 class 定义。

12.2.1 Member functions [class.mfct]

A member function may be defined (11.4) in its class definition, in which case it is an inline member function (10.1.6), or it may be defined outside of its class definition if it has already been declared but not defined in its class definition. A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition.

不是 意味着定义必须出现在 紧邻范围 中。它可以出现在任何封闭的命名空间中,即使那是几层以上。

但是,这是非法的:

namespace a {
    struct X {
        void Y();
    };
}
namespace b { // not an enclosing namespace
    void X::Y()
    {
        std::cout << "Do a thing!\n";
    }
}