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