Summary
In the previous post, I introduced the rules of using directives (using namespace std)
and using declarations (using std::vector)
. Generally speaking, the rules are good if there is no confliction, in which two using-declarations
are the same.
As a quick recap,
using directives
are forbidden. Since this directive makes all names from a namespace available. It is a common cause of collisions and unexpected behavior. Ausing directive
works since it adds another path into the lookup.// Forbidden -- This pollutes the namespace. using namespace foo;
- Use
using-declarations
instead.using-declarations
only take the declared name into the current scope; lookup stops here.
In this post, I want to add more examples to show the behavior of namespace pollution in some edge cases.
Conclusion
Local using-declarations
are better than global using-declarations
. Type alias
like Typedef
or using mytype = int
is even better.
#include <ostream>
//using namespace std; // NO!
//using ::std::cout; // less bad than using namespace, it can be better if we scope it
using cw = console_gui::command_window;
void boo() {
// console_gui::command_window::append("text")
cw::append("text");
}
int main(int argc, char** argv) {
int rc = do_some_stuff(argc, argv);
using ::std::endl;
if (rc) { // print the success report
using ::std::cout;
cout << "The test run completed. The return code was " << rc << '.' << endl;
} else {
using ::std::cerr;
cerr << "Unable to complete the test run." << endl;
}
return 0 == rc;
}
Details
There are several edge cases.
Edge Case 0: The Call is Ambiguous
namespace T {
void flunk(int) { std::cout << "T";}
}
namespace V {
void flunk(int) { std::cout << "V";}
}
int main() {
// 1.
{
using namespace V;
using namespace T;
flunk(1);
}
// 2.
{
using V::flunk;
using T::flunk;
flunk(1);
}
}
The error happens at the compliation time (note that it is not multiple definition in the linking time, since the symbols are in different namespace).
main.cpp: In function ‘int main()’:
main.cpp: error: call of overloaded ‘flunk(int)’ is ambiguous
flunk(1);
Edge Case 1: Specialization in Confliction
The global using declarations
in this post will result in some weird behavior.
namespace mynamespace {
int max(int, int) { return -1;}
}
using std::max;
using mynamespace::max;
int main() {
printf("%d", max(1,2)); // it will print -1
}
Actually it kind-of has "confliction" in this case, it works since the compiler chooses the most specific one as a specialization of the template function max
in std
.
namespace mynamespace {
template<typename T>
T max(T i, T j) { return i;}
}
using std::max;
using mynamespace::max;
int main() {
// 1. error: call of overloaded ‘max(int, int)’ is ambiguous
printf("%d", max(1,2));
}
It will result in the same "Ambiguous" error in case 0.
Edge Case 2: Hide the Lookup
If a local variable has the same name as a namespace variable, the namespace variable is hidden, since it won’t do lookup when the symbol is available included by using-declarations
.
namespace T {
void flunk(int) { std::cout << "T" << std::endl; }
}
namespace V {
void flunk(int) { std::cout << "V" << std::endl; }
}
int main() {
{
using T::flunk;
using namespace V;
flunk(1); // T
}
{
using namespace V;
using T::flunk;
flunk(1); // T
}
{
using V::flunk;
using namespace T;
flunk(1); // V
}
{
using namespace T;
using V::flunk;
flunk(1); // V
}
}