Почему директива using не "связывается" с обычными функциями?

по данным этот вопрос допустимо определять методы класса после using директива, вместо того, чтобы заключать их в namespace блок.

однако это, по-видимому, не относится к обычным функциям. Подумайте:

Greeting.hh

#pragma once

namespace NS
{
    class Greeting
    {
    public:
        void hello();
    };

    void otherHello();
}

Greeting.cc

#include "Greeting.hh"
#include <iostream>

using namespace NS;

void Greeting::hello()
{
    std::cout << "Greeting::hello" << std::endl;
}

void otherHello()
{
    std::cout << "otherHello" << std::endl;
}

main.cc

#include "Greeting.hh"

int main()
{
    NS::Greeting o;
    o.hello();
    NS::otherHello();
}

этот код не будет компилироваться, давая следующее сообщение об ошибке:

undefined reference to `NS::otherHello()'

далее проверка показывает, что otherHelloсимвол не предшествует пространству имен, в то время как Greeting::hello - это:

g++ -std=c++14 -pedantic -Wall -c Greeting.cc
nm -C Greeting.o | grep T
000000000000002a T otherHello()
0000000000000000 T NS::Greeting::hello()

противоречит ли это стандартной ссылке из принято отвечать?

" во время поиска неквалифицированного имени (3.4.1) имена отображаются так, как если бы они были объявлены в ближайшем заключительном пространстве имен, которое содержит оба директива using-и назначенное пространство имен."

1 ответов


важно помнить, что

  1. объявления функций в разных пространствах имен не мешают друг другу.
  2. определение функции также является объявлением.
  3. [пространство имен.def / 4]

заключительные пространства имен объявления - это те пространства имен в которая в декларации лексически значится, за исключением повторное объявление элемент пространства имен вне своего исходного пространства имен (например, определение как указано в [namespace.memdef]). Такая декларация имеет то же самое включение пространств имен в качестве исходного объявления.

Итак, давайте посмотрим на otherHello определение. Где он лексически появляется? В глобальном пространстве имен, конечно. В этом также и смысл декларации. Это означает, что заключительное пространство имен является глобальным, и вы заканчиваете объявлением ::otherHello.

так что нет, это не противоречит стандартной цитате из принятого ответа на другой вопрос. Функции-члены могут быть определены вне класса, если они квалифицированы по их имени класса ([класс.mfct/4]):

если определение функции члена лексически находится вне своего класса определение, имя функции-члена будет квалифицировано своим классом имя с помощью оператора::.

так что нам нужно только спросить,Greeting имя тот же класс, что и NS::Greeting? Да, это так. За это отвечает директива using.


Я добавлю этот сегмент в надежде прояснить. Рассмотрим этот фрагмент кода:

namespace NS1 {
    namespace NS2 {
        void hello();
    }
}

using namespace NS1;

void NS2::hello() {

}

int main() {
    NS1::NS2::hello();
    return 0;
}

когда компилятор встречает NS2::hello определяется его преформ поиск имени для этого id Декларатор. Согласно [basic.уважать.qual / 3]:

в объявлении, в котором Декларатор-id является квалифицированным-id,имена используемый перед объявлением qualified-id просматриваются в определение области пространства имен; просматриваются имена, следующие за квалифицированным-id в рамках класса или пространства имен элемента.

так NS2 просматривается в определяющей области (глобальной), и в соответствии с неквалифицированным правилом поиска имени, которое вы процитировали, оно найдено и разрешено как NS1::NS2. Вот как!--5--> связан с NS1::NS2::hello и разрешен как определяющий его.

в глобальном пространство имен OP,otherHello ничего не предшествует. Поэтому поиск имени не происходит. Он сразу же определяет эту функцию в заключительном пространстве имен, как я ранее цитировал.