Namespaces

Namespaces help disambiguate naming collisions.

Types of namespaces

User-defined namespaces

Use the namespace keyword to define user-defined namespaces.

To access identifiers defined in a namespace, use the scope resolution operator (::): e.g. myNamespace::doSomething().

namespace foo {
  int number = 1;
  void printHello() {
    printf("Hi\n");
  }
}

namespace goo {
  int number = 2;
  void printHello() {
    printf("Hello\n");
  }
}

int main() {
  // Use the scope resolution operator (::)
  // to access identifiers inside a namespace
  printf("%d\n", foo::number); //=> 1
  printf("%d\n", goo::number); //=> 2
  foo::printHello(); //=> Hi
  goo::printHello(); //=> Hello
}

The global namespace

Functions and global variables not defined inside any namespace exist in the global namespace.

To access identifiers in the global namespace, you can:

  • mention their name directly (e.g. doSomething()), or
  • use the scope resolution operator (::) without the namespace name (e.g. ::doSomething()).
// I'm in the global namespace!
int number = 123;

// I'm in the global namespace!
void printWhoami() {
  printf("I'm global!\n");
}

// Explaining the difference between
// `printWhoami` and `::printWhoami`
namespace foo {
  void printWhoami() {
    printf("I'm inside foo!\n");
  }
  void doSomething() {
    printWhoami(); // Calls `printWhoami` in `foo` bamespace
    ::printWhoami(); // Calls `printWhoami` in global namespace
  }
}

int main() {
  printf("%d\n", number);
  //=> 123
  printWhoami();
  //=> I'm global!

  foo::doSomething();
  //=> I'm inside foo!
  //=> I'm global!
}

Multiple namespace block definition

You can define the same namespace name multiple times (e.g. in different files). They will be combined into a single namespace.

// circle.h
namespace basicMath {
  const double pi = 3.14;
}
// growth.h
namespace basicMath {
  const double e = 2.7;
}
// main.cpp
#include <cstdio>
#include "circle.h"
#include "growth.h"

int main() {
  printf("%lf\n", basicMath::pi); //=> 3.140000
  printf("%lf\n", basicMath::e); //=> 2.700000
}

Nested namespaces

You can nest a namespace definition inside a namespace definition.

For example, to create a namespace foo::goo:

// Method 1
namespace foo {
  namespace goo {
    int number = 123;
  }
}

// Method 2 (since C++17)
namespace foo::goo {
  int number = 123;
}

You can then access the identifier as follows:

int main() {
  printf("%d\n", foo::goo::number); //=> 123
}

Unnamed namespace

When you declare an unnamed namespace, they are considered part of the parent namespace.

However, they also imply internal linkage (they can only be seen in the current file). It is as if you have declared global variables or functions with the static keyword.

// Part of the global namespace
// (because it's declared outside any namespace)
// This imply *internal linkage*
namespace {
  int number = 456;
  void printHello() {
    printf("Hi\n");
  }
}

// Declaring these would have the same effect:
// - static int number = 456;
// - static void printHello() {...}

Inline namespaces

Inline namespaces are usually used for versioning. Like unnamed namespaces, they are also considered part of the parent namespace, but hey DO NOT imply internal linkage.

// Also part of the global namespace
// (because it's declared outside any namespace)
inline namespace v1 {
  void printHello() {
    printf("Hi, v1!\n");
  }
}

namespace v2 {
  void printHello() {
    printf("Hi, v2!\n");
  }
}

int main() {
  v1::printHello(); //=> Hi, v1!
  v2::printHello(); //=> Hi, v2!
  // Calls the inline version in the global namespace
  printHello(); //=> Hi, v1!
}

Aliasing namespaces

To alias a namespace in the current scope, use namespace <alias> = <namespace>:

int main() {
  // The `fg` namespace refers to `foo::goo`
  namespace fg = foo::goo;
  // This is the same as accessing `foo::goo::number`
  printf("%d\n", fg::number);
}

The using keyword

using namespace <something>

Also known as using directive, this imports all identifiers from a namespace into the current scope. (It can have block or file scope, depending on where you declare it.)

// Defines `std::cout` and `std::endl`
#include <iostream>
// Now we don't have to specify `std::` again
// (this one have file scope)
using namespace std;

int main() {
  // This actually refers to `std::cout` and `std::endl`
  cout << "Hello world!" << endl;
}

using <something>

Also known as using declaration, this allows us to use specified qualified name (name with scope, e.g. std::cout) without the scope name (e.g. as cout). (It can have block or file scope, depending on where you declare it.)

If naming collision occurs (e.g. between cout and std::cout), then the qualified name (std::cout) will be preferred.

// Defines `std::cout` and `std::endl`
#include <iostream>

int main() {
  // Now we can use `std::cout` and `std::endl` without
  // the `std::` scope (this one have block scope)
  using std::cout;
  using std::endl;
  // This actually refers to `std::cout` and `std::endl`
  cout << "Hello world!" << endl;
}

References