Quote from the 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.
Look at this code:
namespace A {
int fn() { return 1; }
}
namespace Inner {
int fn() { return 2; }
namespace B {
using namespace A;
int z = fn();
}
}
Here, before I knew the exact rules of namespaces, I had expected that z
will be initialized to 1, as I written using namespace A
, so expected that A::fn()
will be used. But it is not the case, z
will be initialized to 2, as Inner::fn()
is called because of the rule I quoted.
What is the rationale behind this behavior: "as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace"?
What would be the cons, if using namespace
worked as applying using declarations for everything in that namespace?
Note: this is the related issue that motivated me to ask this question.
Namespaces are used to organize code into logical groups and to prevent name collisions that can occur especially when your code base includes multiple libraries.
The statement using namespace std is generally considered bad practice. The alternative to this statement is to specify the namespace to which the identifier belongs using the scope operator(::) each time we declare a type.
In C++, a namespace is a collection of related names or identifiers (functions, class, variables) which helps to separate these identifiers from similar identifiers in other namespaces or the global namespace. The identifiers of the C++ standard library are defined in a namespace called std .
A desirable property of a namespace system is that of what I call incremental API compatibility. That is, if I add a symbol to a namespace, then any previously working program should keep working and mean the same thing.
Now, plain C++ with overloads is not incrementally API compatible:
int foo(long x) { return 1; }
int main()
{
foo(0);
}
Now I add the overload int foo(int x) { return 2; }
and the program silently changes meaning.
Anyway, when C++ people designed the namespace
system they wanted that when incrementing an external API, previously working code should not change the namespace from where the symbol is chosen. From your example, the previous working code would be something like:
namespace A {
//no fn here, yet
}
namespace Inner {
int fn() { return 2; }
namespace B {
using namespace A;
int z = fn();
}
}
And z
is easily initialized to 2
. Now augmenting namespace A
with a symbol named fn
will not change the meaning of that working code.
The opposite case does not really apply:
namespace A {
int fn() { return 1; }
}
namespace Inner {
// no fn here
namespace B {
using namespace A;
int z = fn();
}
}
Here z
is initialized to 1
. Of course, if I add fn
to Inner
it will change the meaning of the program, but Inner
is not an external API: actually, when Inner
was written initially, A::fn
did already exist (it was being called!), so there is no excuse for being unaware of the clash.
Imagine this C++98 program:
#include <iostream>
namespace A {
int move = 0;
void foo()
{
using namespace std;
cout << move << endl;
return 0;
}
}
int main()
{
A::foo();
return 0;
}
Now, if I compile this with C++11, everything works fine thanks to this using
rule. If using namespace std
worked as applying using declarations for everything in that namespace, then this program would try to print function std::move
instead of A::move
.
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