I have this sample code
namespace ns1
{
void foo(int)
{
}
}
namespace ns2
{
void foo()
{
}
void bar()
{
using namespace ::ns1;
foo(42); // why compiler can't just call ns1::foo?
}
}
And it doesn't compile with error:
prog.cpp:16:9: error: too many arguments to function ‘void ns2::foo()’
I found reason of this error in C++ 2003 standard:
A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. During unqualified name lookup (3.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace. [Note: in this context, “contains” means “contains directly or indirectly”. ]
Is any rationale for this strange rule? Why names from namespace ns1 can't directly appear in namespace ns2?
I believe this was/is done in an attempt at reducing conflicts and surprises. Names brought into scope by a using
directive are visible, but anything that's directly contained in the local scope will take precedence over it.
If you really want to call you function without a qualified ID, you make it visible with a using
declaration instead:
namespace ns1 {
void foo(int) { }
}
namespace ns2 {
void foo() { }
void bar() {
using ::ns1::foo;
foo(42); // No problem; calls ::ns1::foo.
}
}
ns1::foo
is being hidden by the declaration of ns2::foo
From N3337, §3.3.10/1 [basic.scope.hiding]
A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class (10.2).
The section you've quoted (§7.3.4/2) is immediately followed by
3 A using-directive does not add any members to the declarative region in which it appears. [ Example:
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 example ]
In your case, the using-directive is introducing the names in ns1
to the common ancestor namespace of where it appears, and that of ns1
, meaning the global namespace. It does not introduce them within ns2
, so the declaration of ns2::foo
hides that of ns1::foo
.
If you want ns1::foo
to be found, use a using declaration instead.
void bar()
{
using ::ns1::foo;
foo(42);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With