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