Я не понимаю 3.4 / 2 в Стандарте:
Имя «посмотрел вверх в контексте выражения» выглядит как
неполное имя в области, в которой найдено выражение.
Что делать, если имя квалифицировано, как N::i
ниже?
#include <iostream>
namespace N { int i = 1; }
int main()
{
int i = 0;
std::cout << N::i << '\n';
}
Квалифицированное имя N::i
не ищется в области, где N::i
найден, то есть он не был найден в области видимости main () и глобальной области видимости!
Чтобы расширить комментарий @JerryCoffin, правила для квалифицированного поиска:
3.4.3 Поиск по квалифицированному имени [basic.lookup.qual]
3 В объявлении, в котором идентификатор объявления является квалифицированным идентификатором, имена
используется до того, как объявленный квалифицированный идентификатор ищется в
определение объема пространства имен; имена, следующие за определенным идентификатором, ищутся
в рамках класса члена или пространства имен.
Вот пример:
#include <iostream>
struct N { enum { i = 1 }; };
int main()
{
std::cout << N::i << '\n'; // prints 1
struct N { enum { i = 0 }; };
std::cout << N::i << '\n'; // prints 0
}
Сначала левая сторона ::
смотрит вверх, а затем правая сторона смотрит вверх внутри него. Итак, чтобы посмотреть N::i
сначала находит N
используя неквалифицированный поиск, то он заглядывает внутрь N
найти i
, Просто!
В вашем примере вы переопределяете N
на местном уровне. После локального определения внешнее определение скрыто согласно §3.3.10: «Имя может быть скрыто явным объявлением того же имени во вложенной декларативной области или производном классе».
Поскольку компилятор с самого начала знает, что левая часть (N
) должен выдавать тип, пространство имен или перечисление, любые другие результаты поиска (то есть функции, переменные и шаблоны) игнорируются. Итак, вы также можете сделать:
#include <iostream>
struct N { enum { i = 1 }; };
int main()
{
int N = 3;
std::cout << N::i << '\n'; // prints 1
std::cout << N << '\n'; // prints 3
struct N { enum { i = 0 }; };
std::cout << N::i << '\n'; // prints 0
}
http://coliru.stacked-crooked.com/a/9a7c9e34b1e74ce7
См. §3.4.3 / 1:
На имя члена класса или пространства имен или перечислителя можно ссылаться после
::
Оператор разрешения области действия (5.1) применяется к спецификатору вложенного имени, который обозначает его класс, пространство имен или перечисление. Если::
Оператору разрешения области действия в спецификаторе вложенного имени не предшествует спецификатор decltype, поиск имени которого предшествует::
рассматривает только пространства имен, типы и шаблоны, специализация которых — типы. Если найденное имя не обозначает пространство имен или класс, перечисление или зависимый тип, программа является некорректной.