类成员函数在其名称空间之外定义

时间:2019-07-04 12:47:16

标签: c++ c++11 namespaces using-directives name-lookup

以下代码可与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声称,如果成员函数是在其类的外部定义的,则必须在该类的命名空间中对其进行定义。有关member functions,请参见cppreference页面的顶部。

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

3 个答案:

答案 0 :(得分:4)

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

  

出现在类定义之外的成员函数定义   应该出现在包含类定义的名称空间范围中。

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

答案 1 :(得分:4)

  

12.2.1成员函数[class.mfct]

     

成员函数可以在其类定义中定义(11.4),在这种情况下,它是一个 inline 成员函数(10.1.6),或者可以在其类定义之外定义它它已被声明,但尚未在其类定义中定义。出现在类定义之外的成员函数定义应出现在包含类定义的名称空间范围中。

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

但是,这将是非法的:

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

答案 2 :(得分:2)

using namespace ns;

  

5)使用指令:从使用指令之后的任何名称的非限定名称查找的角度来看,直到出现该名称的范围结束为止,ns_name中的每个名称都是可见的,就像在最接近的封闭名称空间,其中包含using-directive和ns_name。

这意味着在当前作用域ns中,寻址该命名空间中的某些内容可以忽略。

这样,当您编写此代码时:

using namespace std;
vector<string> vectorofstrings;

您不必写

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

类的namespace是类的名称。因此,如果您有:

namespace aNamespace{

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

}

然后,完全限定的查找为::aNamespace::aClass,并且必须将一个函数定义为void ::aNamespace::aClass::aFunction(){}的一部分