У меня есть этот фрагмент кода
#include <iostream>
namespace ns{
int a = 10;
}
using namespace ns;
int a = 20;
int main(){
std::cout << a;
}
Насколько я понимаю, когда std::cout << a
оценивается, a
ищется в локальной области main
. Если он не найден, поиск выполняется в глобальной области, где находится a
. Итак, я просто ожидал, что он напечатается 20
, но код не компилируется, утверждая, что
error: reference to 'a' is ambiguous
Однако этот код работает:
#include <iostream>
namespace ns{
int a = 10;
}
using namespace ns;
int a = 20;
int main(){
std::cout << ::a;
}
Он печатает 20
. Почему возникает эта разница? Разве эти два кода не должны быть эквивалентными, учитывая, что a
не определен в области main
, а поиск в обоих случаях выполняется в глобальной области?
Это связано с похожим вопросом, но я хочу конкретно понять разницу, вызванную заменой a
на ::a
, и то, что эти два слова не эквивалентны, а не просто неоднозначные ссылки на переменные.
оба a
можно найти в глобальном пространстве имен.
@ 463035818_is_not_an_ai То же самое и во втором фрагменте кода, не так ли?
@RajdeepSindhu да, но, как поясняет ответ, только в первом случае вы просите компилятор искать все a
, которые он может найти. Во втором вы специально запрашиваете тот, который объявлен в глобальной области видимости.
using namespace
влияет только на неполный поиск имени. Во втором примере вы явно ссылаетесь на ::a
, символ в глобальной области видимости. Компилятор знает, что вы имеете в виду, все в порядке.
Но в первом случае вы ссылаетесь только на a
без какого-либо квалификатора области, поэтому компилятор выполняет поиск, чтобы выяснить, какой a
вы имеете в виду, и здесь возникают проблемы, поскольку и ::a
, и импортированный ns::a
видны.
Если using namespace
влияет только на поиск неполных имен, то почему работает второй фрагмент кода, если мы удалим глобальный int a = 20;
? На квалифицированный поиск a
влияет директива using, не так ли?
Взгляните на https://en.cppreference.com/w/cpp/language/namespace, особенно на
Директива using не добавляет никаких имен в декларативную область, в которой она появляется (в отличие от декларации using), и, таким образом, не предотвращает объявление идентичных имен.
Поскольку вы «всего лишь» используете using ns
вместо using ns::a
, вы не вводите a
в глобальное пространство имен. Вы просто говорите компилятору искать в пространстве имен ns
в дополнение к глобальному.
Таким образом, когда вы объявляете переменные a
, проблем не возникает, поскольку одна из них находится в ns
, а другая — в глобальном пространстве имен. Однако когда вы ищете неквалифицированный a
, все члены ns
также считаются частью глобального пространства имен (из-за using
), поэтому теперь в одном пространстве имен есть два a
.
Во втором примере ::a
явно указывает использовать глобальное пространство имен; это больше не неквалифицированный поиск. По этому поводу https://en.cppreference.com/w/cpp/language/qualified_lookup есть следующее:
Квалифицированный поиск в области пространства имен N сначала рассматривает все объявления, расположенные в N... Если в этом наборе нет объявлений, то он рассматривает объявления во всех пространствах имен, названных директивами using, найденными в N...
Другими словами, «используемые» пространства имен рассматриваются ПОСЛЕ фактического пространства имен, поэтому двусмысленности больше нет.
Спасибо за ответ. Может быть, это немного не связано, но будет ли использование using namespace ns
внутри main
также сообщать компилятору о необходимости поиска ns
в дополнение к глобальному пространству имен, или оно скажет компилятору искать ns
в дополнение к локальному пространству имен main
?
В рамках main()
использование using namespace ns
в вопросе имеет тот же эффект, что и использование using namespace ns
в main()
.
Рассмотрим первый код. И подумайте, что произойдет, если программисты просто задумаются использовать ns::a. Так что это хорошая возможность — допускать явные программные ошибки, которые будет сложно найти. Мы не (современные) компьютеры/компиляторы, поэтому вам следует думать, что компьютерные языки также учитывают человеческий фактор (а не только простую семантику).