Используя директиву - почему так странное поведение?
У меня есть этот пример кода
namespace ns1
{
void foo(int)
{
}
}
namespace ns2
{
void foo()
{
}
void bar()
{
using namespace ::ns1;
foo(42); // why compiler can't just call ns1::foo?
}
}
И он не компилируется с ошибкой:
prog.cpp:16:9: error: too many arguments to function ‘void ns2::foo()’
Я нашел причину этой ошибки в стандарте С++ 2003:
Директива using указывает, что имена в номинированном пространстве имен может использоваться в области, в которой появляется директива use после директива use. При поиске неквалифицированного имени (3.4.1), имена отображаются так, как если бы они были объявлены в ближайшем охватывающем пространстве имен который содержит как директиву, так и назначенное пространство имен.[Примечание: в этом контексте "содержит" означает "содержит непосредственно или косвенно".]
Является ли любое обоснование для этого странного правила? Почему имена из пространства имен ns1 не могут непосредственно отображаться в пространстве имен ns2?
Ответы
Ответ 1
Я считаю, что это было/сделано в попытке уменьшить конфликты и сюрпризы. Имена, введенные в область видимости с помощью директивы using
, видны, но все, что непосредственно содержится в локальной области, будет иметь приоритет над ней.
Если вы действительно хотите вызвать функцию без квалифицированного идентификатора, вы делаете ее видимой с помощью объявления using
:
namespace ns1 {
void foo(int) { }
}
namespace ns2 {
void foo() { }
void bar() {
using ::ns1::foo;
foo(42); // No problem; calls ::ns1::foo.
}
}
Ответ 2
ns1::foo
скрывается декларацией ns2::foo
Из N3337, §3.3.10/1 [basic.scope.hiding]
Имя может быть скрыто явным объявлением того же имени во вложенной декларативной области или производном классе (10.2).
В разделе, которое вы указали (§7.3.4/2), сразу следует
3 Директива using не добавляет никаких членов в декларативный регион, в котором он появляется. [Пример:
namespace A {
int i;
namespace B {
namespace C {
int i;
}
using namespace A::B::C;
void f1() {
i = 5; // OK, C::i visible in B and hides A::i
}
}
// more (irrelevant) stuff
}
-end пример]
В вашем случае директива using вводит имена в ns1
в пространство имен общих предков, где оно появляется, и имя ns1
, что означает глобальное пространство имен. Он не вводит их в пределах ns2
, поэтому объявление ns2::foo
скрывает значение ns1::foo
.
Если вы хотите найти ns1::foo
, используйте вместо этого использование объявления.
void bar()
{
using ::ns1::foo;
foo(42);
}