Skip to content

Namespaces

Overview

C++'s namespace mechanism can be used to resolve name conflicts in complex projects.

For example: All contents of the C++ standard library are defined within the std namespace. If you define a variable named cin, you can access your defined cin variable via cin, and access the standard library's cin object via std::cin, without worrying about conflicts.

Declaration

The following code declares a namespace named A:

1
2
3
4
5
namespace A {
int cnt;

void f(int x) { cnt = x; }
}  // namespace A

After declaration, outside this namespace, you can access the f function inside namespace A via A::f(x), and access the cnt variable inside namespace A via A::cnt.

Namespace declarations can be nested, so the following code is also allowed:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
namespace A {
namespace B {
void f() { ... }
}  // namespace B

void f() {
  B::f();  // Actually accesses A::B::f(). Since we are currently inside 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, if you want to access members inside the namespace from outside, you need to prefix the member name with namespace::.

Is there a convenient way to directly access members inside a namespace using just the member name? The answer is yes. We can use the using directive.

The using directive has the following two forms:

  1. using namespace::member;: This directive allows us to omit the namespace before a specific member name and access the member directly via the member name, effectively importing this member into the current scope.
  2. using namespace namespace;: This directive allows direct access to any member within the namespace using just the member name, effectively importing all members of this namespace into the current scope.

Therefore, if using namespace std; is executed, all names from std are introduced into the global namespace within the current scope. This allows us to 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 from std, if you declare a variable or function with the same name as one in std, it may cause a compilation error due to a name conflict.

Therefore, in engineering projects, using the using namespace namespace; directive is not recommended.

With the using directive, the code from C++ Syntax Basics can be written equivalently in these two ways:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#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;
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <iostream>

using namespace std;

int main() {
  int x, y;
  cin >> x >> y;
  cout << y << endl << x;
  return 0;
}

Unnamed Namespace

When we define a namespace within a scope solely to prevent name conflicts, its definition and usage can become very concise. We can use an unnamed namespace.

A namespace defined like namespace { /* something ... */ } (omitting the namespace name) is called an unnamed namespace. An unnamed namespace within a file is considered to have a unique name, different from all other namespaces, but multiple unnamed namespaces within the same scope are considered the same namespace. After an unnamed namespace is defined, the names within it can be found for use in the outer scope, as if a using namespace directive was added after the unnamed namespace definition.

Applications

Preventing Name Conflicts Between Subtasks

In problems with multiple subtasks, we can define a namespace for each subtask, declaring the variables and functions needed to solve that subtask within it. This way, even if two subtask implementations declare the same name, they won't conflict, making the subtasks independent of each other. This can facilitate debugging to some extent and improve program readability.

Preventing Conflicts with Standard Library and Environment-Introduced Names

Using namespaces can also prevent conflicts between names commonly used in competitive programming and standard names, as shown in the following example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#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, typically, there will be a conflict on Linux but not on Windows.

void solve() {
  // Using our declared end and y1 without qualification (no ::) inside Sol::solve()
  // will not cause a name conflict; whereas if the above code were in the global namespace,
  // it would cause conflicts: end would only conflict with std::end during name lookup
  // (i.e., when compiling the code that uses it), while y1 would conflict at declaration;
  // and the conflict with y1, being environment-dependent, might not be detected on Windows
  // but would cause a compilation error in the Linux judging environment.
}
}  // namespace Sol

int main() { Sol::solve(); }

References