Я не понимаю 3.4/2 в стандарте

Я не понимаю 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() и глобальной области видимости!


person Mao    schedule 28.06.2014    source источник
comment
3.4/2 — это определение того, что ищет в контексте выражения. Он не требует поиска всех имен в контексте выражения, в котором они появляются. Поиск в контексте выражения является одним механизмом поиска; другими механизмами поиска являются квалифицированный поиск и ADL.   -  person dyp    schedule 28.06.2014
comment
Поскольку имя квалифицировано, оно ищется по правилам [basic.lookup.qual] (§3.4.3).   -  person Jerry Coffin    schedule 28.06.2014


Ответы (2)


Чтобы расширить комментарий @JerryCoffin, правила квалифицированного поиска:

3.4.3 Поиск полного имени [basic.lookup.qual]

3 В объявлении, в котором declarator-id является qualified-id, имена, использованные до объявления qualified-id, ищутся в определяющей области пространства имен; имена, следующие за qualified-id, ищутся в области видимости класса члена или пространства имен.

Вот пример:

#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
}

Живой пример.

person TemplateRex    schedule 29.06.2014
comment
Там нет объявления квалифицированного идентификатора. Это правило реализует то, как, например, объявление функции-члена может объявлять параметры типа члена без повторения квалификации для каждого параметра. - person Potatoswatter; 18.06.2015

Сначала просматривается левая часть ::, а затем просматривается правая часть внутри него. Таким образом, чтобы найти 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, поиск имени, предшествующего этому ::, рассматривает только пространства имен, типы и шаблоны, специализации которых являются типами. Если найденное имя не указывает ни пространство имен, ни класс, ни перечисление, ни зависимый тип, программа некорректна.

person Potatoswatter    schedule 18.06.2015