Overview
C++'s namespace mechanism can be used to solve name conflicts in complex projects.
For example, all contents of the C++ standard library are defined in the std namespace. If you define a variable named cin, you can access your cin variable through cin and access the standard library's cin object through std::cin without worrying about conflicts.
Declaration
The following code declares a namespace named A:
namespace A {
int cnt;
void f(int x) { cnt = x; }
} // namespace A
After the declaration, outside this namespace, you can access the f function inside namespace A through A::f(x), and the cnt variable inside namespace A through A::cnt.
Namespace declarations can be nested, so the following code is also valid:
namespace A {
namespace B {
void f() { ... }
} // namespace B
void f() {
B::f(); // Actually accesses A::B::f(); since it is currently in namespace A
// the preceding A:: can be omitted
}
} // namespace A
void f() // This defines the f function in the global namespace, which does not
// conflict with A::f or A::B::f
{
A::f();
A::B::f();
}
The using directive
After declaring a namespace, when accessing a member inside it from outside the namespace, you need to prepend 命名空间:: to the member name.
Is there a convenient way to access members in a namespace directly by their member names? The answer is yes. We can use a using directive.
The using directive has the following two forms:
using 命名空间::成员名;: this directive lets us omit the namespace before a member name and access the member directly by its name, which is equivalent to importing this member into the current scope.using namespace 命名空间;: this directive lets us access any member in the namespace directly by its member name, which is equivalent to importing all members of the namespace into the current scope.
Therefore, if using namespace std; is executed, all names in std are introduced into the global namespace in the current scope. We can then use cin instead of std::cin and cout instead of std::cout.
The using directive may cause name conflicts!
Since using namespace std; introduces all names in std, declaring a variable or function with the same name as one in std may cause a compilation error due to a name conflict.
Therefore, using the using namespace 命名空间; directive is not recommended in engineering projects.
With the using directive, the code in C++ syntax basics can be written in these two equivalent ways:
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main() {
int x, y;
cin >> x >> y;
cout << y << endl << x;
return 0;
}
#include <iostream>
using namespace std;
int main() {
int x, y;
cin >> x >> y;
cout << y << endl << x;
return 0;
}
Unnamed namespaces
When a namespace used only to prevent name conflicts is defined in a scope, its definition and use can be made much simpler. We can use an unnamed namespace.
A namespace defined in the form namespace { /* something ... */ } (with the namespace name omitted) is called an unnamed namespace. An unnamed namespace in a file is considered to have a unique name, different from all other namespaces, but multiple unnamed namespaces in the same scope are considered to be the same namespace. After an unnamed namespace is defined, names in it can be found when used in scopes outside it, as though a using namespace directive had been added after the definition of the unnamed namespace.
Applications
Preventing name conflicts between subtasks
In problems with multiple subtasks, we can define a namespace for each subtask and define the variables and functions needed to solve that subtask inside it. Then, even if the implementations of two subtasks declare names that are the same, they will not conflict. This keeps the subtasks from interfering with one another, which makes debugging easier to some extent and also improves program readability.
Preventing name conflicts with names introduced by the standard library and the environment
Namespaces can also prevent conflicts between names commonly used in algorithm competitions and names from the standard library, as in the following example:
#include <math.h>
#include <vector>
using namespace std;
namespace Sol {
int end; // std::end is introduced by using namespace std;
int y1; // y1 is the Bessel function of the second kind defined by POSIX
// Therefore, there is usually a conflict on Linux but not on Windows
void solve() {
// Using our declared end and y1 without qualification (without ::) in Sol::solve()
// does not cause a name conflict; if the above code were in the global namespace, it would cause a conflict: end
// would conflict with std::end only during name lookup (that is, when the code using it is compiled), while y1
// would conflict at declaration; moreover, because the conflict involving y1 depends on the environment, it might not be detected on Windows
// but would cause a compilation error in the Linux judging environment.
}
} // namespace Sol
int main() { Sol::solve(); }