Функция-член класса, определенная вне его пространства имен - PullRequest
3 голосов
/ 04 июля 2019

Следующий код прекрасно компилируется с последними версиями MSVC, GCC и CLang, доступными на сайте исследователя компиляторов godbolt.Интересно, почему:

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 утверждает, что если функция-член определена вне своего класса, то она должна быть определена в пространстве имен этого класса.См. Самый верх страницы cppreference о функциях-членах .

Но, тем не менее, компиляторы принимают код.Маловероятно, что все три независимых компилятора имеют одну и ту же ошибку, верно?Итак, есть ли веская причина для того, чтобы они приняли такой код?

Ответы [ 3 ]

4 голосов
/ 04 июля 2019

Цитирование C ++ 17 (n4659) 12.2.1 [class.mfct] / 1:

Определение функции-члена, которая появляется вне определения класса должен появиться в области имен, содержащей определение класса.

Это означает, что он должен быть определен в пространстве имен, которое содержит класс, или в любом родительском пространстве имен этого пространства имен. В вашем случае он определен в глобальном пространстве имен, которое действительно (косвенно) включает определение класса.

4 голосов
/ 04 июля 2019

12.2.1 Функции-члены [class.mfct]

Функция-член может быть определена (11.4) в своем определении класса, и в этом случае она является встроенным членомфункция (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 голосов
/ 04 июля 2019

using namespace ns;

5) директива using: с точки зрения поиска безусловного имени любого имени после директивы using и до концав области, в которой оно появляется, каждое имя из ns_name является видимым, как если бы оно было объявлено в ближайшем окружающем пространстве имен, которое содержит как директиву using, так и 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(){}

...