Namespaces

"The road to hell is paved with global variables" -- Steve McConnell

Namespaces

A simple program with 4 global symbols:
#include <iostream>  // cout, endl

int foo = 1;         // foo in global namespace
int bar = 2;         // bar in global namespace

int Div2(int value) // Div2 in global namespace
{
  return value / 2;
}

int main() // main in global namespace
{
  std::cout << foo << std::endl;     // use global foo
  std::cout << bar << std::endl;     // use global bar
  std::cout << Div2(8) << std::endl; // use global Div2
  return 0;
}
However, placing these symbols in a namespace will prevent the program from compiling:
int main()
{
  std::cout << foo << std::endl;     // error, foo is undefined
  std::cout << bar << std::endl;     // error, bar is undefined
  std::cout << Div2(8) << std::endl; // error, Div2 is undefined
  return 0;
}
We need to qualify the symbols in the namespace:
int main()
{
  std::cout << IntroCppProgramming::foo << std::endl;     
  std::cout << IntroCppProgramming::bar << std::endl;     
  std::cout << IntroCppProgramming::Div2(8) << std::endl; 
  return 0;
}
The general form of a namespace definition is:
namespace user-defined-name
{
  declaration/definition
  declaration/definition
  ...
}

Scope Resolution Operator

Example:
#include <iostream> // cout, endl

int foo = 1; // global
int bar = 2; // global

void fn1()
{
  int foo = 10;    // local foo #1 hides global foo
  int bar = foo;   // local bar #1 hides global bar (set to local foo)
  int baz = ::foo; // local baz #1 is set to global foo

  if (bar == 10)   // local bar #1
  {
    int foo = 100; // local foo #2 hides local #1 and global
    bar = foo;     // local bar #1 is set to local foo #2
    foo = ::bar;   // local foo #2 is set to global bar
  }

  ::foo = foo;   // global foo is set to local foo #1
  ::bar = ::foo; // global bar is set to global foo

  std::cout << "foo is " << foo << std::endl;     // local foo #1 is 10
  std::cout << "bar is " << bar << std::endl;     // local bar #1 is 100
  std::cout << "::foo is " << ::foo << std::endl; // global foo is 10
  std::cout << "::bar is " << ::bar << std::endl; // global bar is 10
}
Marked-up diagram

Notes:

Nested Namespaces

Eventually, even a namespace is going to have hundreds or thousands of symbols. Example:
#include <iostream> // cout, endl

namespace DigiPenInstituteOfTechnology
{
  int Div2(int x) {return x * 0.5;}
  
  namespace IntroductoryProgramming
  {
    int Div2(int x) {return x / 2;}
  }

  namespace AdvancedProgramming
  {
    int Div2(int x) {return x >> 1;}
  }
}

int main(void)
{
  std::cout << DigiPenInstituteOfTechnology::Div2(8) << std::endl;
  std::cout << DigiPenInstituteOfTechnology::IntroductoryProgramming::Div2(8) << std::endl;
  std::cout << DigiPenInstituteOfTechnology::AdvancedProgramming::Div2(8) << std::endl;

  return 0;
}

Unnamed Namespaces

What happens when we run out of unique names for namespaces?
#include <iostream> // cout, endl

namespace
{
  double sqrt(double x) { return x; }
}

int main()
{
  std::cout << sqrt(25.0) << std::endl;   // No qualification needed
  return 0;
}
If we have a symbol in an unnamed namespace that is the same as a global symbol in our program, we won't be able to access the symbol in the unnamed namespace.

Example: (Ignore the fact that the sqrt functions don't work)

#include <iostream> // cout, endl
#include <cmath>    // sqrt

namespace
{
  double sqrt(double x) { return x; }; // Line 6: available only in this file 
}

double sqrt(double x) { return x; };   // Line 9: global 

int main()
{
  std::cout << ::sqrt(25.0) << std::endl;      // Global sqrt function defined in this file
  std::cout << std::sqrt(25.0) << std::endl;   // sqrt from std namespace
  std::cout << sqrt(25.0) << std::endl;        // Line 15: Ambiguous (from global or unnamed namespace?)
  
  return 0;
}
These are the error messages from the GNU compiler:
sqrt.cpp: In function 'int main()':
sqrt.cpp:15: error: call of overloaded 'sqrt(double)' is ambiguous
sqrt.cpp:9: note: candidates are: double sqrt(double)
sqrt.cpp:6: note:  double::sqrt(double)

Design Tip
When hiding symbols at the file scope, prefer to use unnamed namespaces over the already-overloaded-too-much C static keyword.

Namespace Aliases

Given these namespaces:
namespace AdvancedProgramming 
{
  int foo = 11;    
  int bar = 12;    
  int f1(int x)  { return x / 2; }
}

namespace IntroductoryProgramming
{
  int foo = 21;    
  int bar = 22;    
  int Div2(int x) {return x / 2; }
}

using them requires a lot of typing:
int main()
{
  std::cout << AdvancedProgramming::foo << std::endl;
  std::cout << IntroductoryProgramming::Div2(8) << std::endl;

  return 0;
}
To allow unique namespaces and to shorten the names, you can create a namespace alias
  // Declare these after the namespace definitions above
namespace AP = AdvancedProgramming;
namespace IP = IntroductoryProgramming;

int main()
{
    // Now, use the shorter aliases
  std::cout << AP::foo << std::endl;
  std::cout << IP::foo << std::endl;
  
  std::cout << AP::f1(8) << std::endl;
  std::cout << IP::Div2(8) << std::endl;

  return 0;
}

void fn1()
{
    // You can "re-alias" a namespace (must be in different scope)
  namespace AP = IntroductoryProgramming;

  std::cout << AP::f1(8) << std::endl;   // Now, an error no f1 in AP
  std::cout << AP::Div2(8) << std::endl; // Ok
  std::cout << IP::Div2(8) << std::endl; // Same as above
}

Notes:


Creating aliases for nested namespaces as well:


namespace AdvancedProgramming
{
  int Div2(int x) {return x >> 1;}
}

namespace AP = AdvancedProgramming;

namespace DigiPenInstituteOfTechnology
{
  int Div2(int x) {return x / 2;}
  
  namespace IntroductoryProgramming
  {
    int Div2(int x) {return x / 2;}
  }

  namespace AdvancedProgramming
  {
    int Div2(int x) {return x >> 1;}
  }
}
namespace DIT = DigiPenInstituteOfTechnology;
namespace DIT_IP = DigiPenInstituteOfTechnology::IntroductoryProgramming;
namespace DIT_AP = DIT::AdvancedProgramming;  // uses previous alias

  // multiple aliases
namespace CS120 = DIT::IntroductoryProgramming;
namespace CS225 = DIT::AdvancedProgramming;

int main(void)
{
    // These are all equivalent
  std::cout << DigiPenInstituteOfTechnology::IntroductoryProgramming::Div2(8) << std::endl;
  std::cout << DIT::IntroductoryProgramming::Div2(8) << std::endl;
  std::cout << DIT_IP::Div2(8) << std::endl;
  std::cout << CS120::Div2(8) << std::endl;

    // These are equivalent
  std::cout << DIT_AP::Div2(8) << std::endl;
  std::cout << CS225::Div2(8) << std::endl;

  return 0;
}
Note that you can't do this:
    // DigiPenInstituteOfTechnology::AdvancedProgramming::foo??
  cout << DIT::AP::foo << endl;             
because AP is not a member of the DIT namespace. (It's not a substitution like the preprocessor performs with a #define.)

Another example:

namespace DigiPenInstituteOfTechnology
{
  namespace GAM400
  {
    namespace Graphics
    {
      // stuff here
    }

    namespace Physics
    {
      // stuff here
    }

    namespace Network
    {
      // stuff here
    }
  }
}
Now, with one alias like this:
namespace DIT = DigiPenInstituteOfTechnology;
You can access symbols inside the hierarchy something like this (assume there is an initialize function in each):
DIT::GAM400::Graphics::initialize();
DIT::GAM400::Physics::initialize();
DIT::GAM400::Network::initialize();
DIT::GAM350::Graphics::initialize(); 
DIT::PRJ450::Network::initialize();  
It may seem like a lot of typing, but it is very clear what is going on. It is not unusual to have lots of modules in your program that all have an initialize or init function. This is better than having several global functions with names like this:
Gam400_Graphics_initialize();
Gam400_Physics_initialize();
Gam400_Network_initialize();
Gam350_Graphics_initialize();
PRJ450::Network::initialize();
Global symbols tend to have very long names in order to minimize the chance of name collisions. Local symbols can't conflict with other local symbols, so they have much shorter names.

Design Tip
Don't create very terse namespaces (like std). Create unique and meaningful namespaces and let the user create shorthand notation with aliases.

Using Declarations

A using declaration allows you to make specific symbols accessible without requiring the namespace and scope resolution operator.

Example:

 1.   namespace Stuff
 2.   {
 3.     int foo = 11; // Stuff::foo
 4.     int bar = 12; // Stuff::bar
 5.     int baz = 13; // Stuff::baz
 6.   }
 7.   
 8.   using Stuff::foo; // Make foo globally accessible to all code below
 9.                     // without namespace qualifier
10.   
11.   void f1()
12.   {
13.     Stuff::foo = 21;   // OK, using namespace
14.     foo = 22;          // OK, namespace not required
15.   
16.     using Stuff::bar;  // Make bar available to code below (in this scope/function only) 
17.     bar = 30;          // OK
18.   }
19.   
20.   void f2()
21.   {
22.     int foo = 3;    // This is a new foo, it hides Stuff::foo
23.     Stuff::foo = 4; // OK, qualified
24.     ::foo = 5;      // OK, global foo (i.e. Stuff::foo)
25.   }
26.   
27.   int main()
28.   {
29.     foo = 23;         // OK because of using declaration above
30.   
31.     using Stuff::baz; // Make baz available in this function only
32.     baz = 40;         // OK
33.   
34.     return 0;
35.   }
Summary:
 1.   using Stuff::baz; // 'Stuff' has not been declared yet
 2.   
 3.   namespace Stuff
 4.   {
 5.     int foo = 11; // Stuff::foo
 6.     int bar = 12; // Stuff::bar
 7.     int baz = 13; // Stuff::baz
 8.   }
 9.   
10.   namespace Stuff2
11.   {
12.     int bar = 111; // Stuff2::bar
13.   }
14.   
15.   using Stuff::foo; // Make foo globally accessible to all code below
16.                     // without namespace qualifier
17.   
18.   void f1()
19.   {
20.     Stuff::foo = 21;   // OK, using namespace
21.     foo = 22;          // OK, namespace not required
22.     bar = 30;          // Error, Stuff:: namespace required
23.   
24.     using Stuff::bar;  // Make bar available to code below (in this scope/function only) 
25.     bar = 30;          // OK
26.   
27.     int bar = 5;       // Error: redeclaration. The using declaration above already declared it
28.   
29.     using Stuff2::bar; // Error: redeclaration. The using declaration above already declared it
30.   }
31.   
32.   int foo = 222;       // Error:  redeclaration. The using declaration above already declared it
33.   
34.   int main()
35.   {
36.     foo = 23;         // OK because of using declaration above
37.     bar = 30;         // Error, bar needs namespace
38.   
39.     using Stuff::baz; // Make baz available in this function only
40.     baz = 40;         // OK
41.   
42.     return 0;
43.   }
Errors generated by the clang compiler:
udecls2.cpp:1:7: error: use of undeclared identifier 'Stuff'
using Stuff::baz; // 'Stuff' has not been declared yet
      ^
udecls2.cpp:22:3: error: use of undeclared identifier 'bar'
  bar = 30;          // Error, Stuff:: namespace required
  ^
udecls2.cpp:27:7: error: declaration conflicts with target of using declaration already in scope
  int bar = 5;       // Error: redeclaration. The using declaration above already declared it
      ^
udecls2.cpp:6:7: note: target of using declaration
  int bar = 12; // Stuff::bar
      ^
udecls2.cpp:24:16: note: using declaration
  using Stuff::bar;  // Make bar available to code below (in this scope/function only) 
               ^
udecls2.cpp:29:17: error: target of using declaration conflicts with declaration already in scope
  using Stuff2::bar; // Error: redeclaration. The using declaration above already declared it
                ^
udecls2.cpp:12:7: note: target of using declaration
  int bar = 111; // Stuff2::bar
      ^
udecls2.cpp:6:7: note: conflicting declaration
  int bar = 12; // Stuff::bar
      ^
udecls2.cpp:32:5: error: declaration conflicts with target of using declaration already in scope
int foo = 222;    // Error:  redeclaration. The using declaration above already declared it
    ^
udecls2.cpp:5:7: note: target of using declaration
  int foo = 11; // Stuff::foo
      ^
udecls2.cpp:15:14: note: using declaration
using Stuff::foo; // Make foo globally accessible to all code below
             ^
udecls2.cpp:37:3: error: use of undeclared identifier 'bar'
  bar = 30;         // Error, bar needs namespace
  ^
6 errors generated.
Note: The errors are detected when the using declaration is encountered, not when the symbol is accessed:
using Stuff::bar;  // Make bar available in this scope.
using Stuff2::bar; // Error is detected here: redeclaration. The using declaration above already declared it

bar = 30;          // Which bar? The compiler never reaches this to see the ambiguity.

Using Directives

A using directive allows you to make all of the names in a namespace visible at once:

More detailed example:
namespace Stuff
{
  int foo = 11;       // Stuff::foo     
  int bar = 12;       // Stuff::bar         
  int baz = 13;       // Stuff::baz     
}

void f1()
{
  int foo = 3;        // local, hides nothing
  int x = Stuff::foo; // OK
  int y = bar;        // error, bar is unknown
}

int foo = 20;         // global ::foo 

int main()
{
  using namespace Stuff;                // Stuff's members are now accessible without Stuff::
                                        //  qualifier within main
  std::cout << ::foo << std::endl;      // no problem, global
  std::cout << Stuff::foo << std::endl; // no problem, Stuff::foo
  std::cout << foo << std::endl;        // error, foo is ambiguous (global ::foo or Stuff::foo?) 

  std::cout << bar << std::endl;  // Stuff::bar
  std::cout << baz << std::endl;  // Stuff::baz

  int foo = 3;        // OK, hides Stuff::foo and global ::foo 
  int x = Stuff::foo; // OK, use qualified name
  x = foo;            // OK, local foo above
  x = ::foo;          // OK, global foo

  return 0;
}

Summary:

Using directives were designed for backward-compatibility with existing C++ code (which doesn't understand namespaces) to help support older code. They should be used cautiously when writing new code, especially if they are used at a global scope.

The Standard Namespace (std)

Now that we've seen some of the details of how namespaces are created and used, we can see how they can be applied.

Now we can write code like this (to ensure job security):
#include <iostream> // For cout and endl;

int main()
{
  int cout = 16;  // cout is an int
  cout << 1;      // no effect
  std::cout << cout << 3 << std::endl;   // std::cout is a stream, prints: 163
  std::cout << (cout << 3) << std::endl; // std::cout is a stream, prints: 128
  return 0;
}
Operator precedence chart for C++

Here's a classic example of the problem with a using directive:
#include <algorithm> // STL functions
using namespace std; // make the whole C++ universe available!

int count = 0;

int increment()
{
  return ++count; // error, identifier count is ambiguous
}
Error message:
count.cpp: In function 'int increment()':
count.cpp:8:12: error: reference to 'count' is ambiguous
   return ++count; // error, identifier count is ambiguous
            ^~~~~
count.cpp:4:5: note: candidates are: int count
 int count = 0;
     ^~~~~
In file included from /usr/include/c++/7/algorithm:62:0,
                 from count.cpp:1:
/usr/include/c++/7/bits/stl_algo.h:4076:5: note: 
     template typename std::iterator_traits<_Iterator>::difference_type std::count(_IIter, _IIter, const _Tp&)
     count(_InputIterator __first, _InputIterator __last, const _Tp& __value)
     ^~~~~
Hopefully, that should convince you that using directives should be used judiciously.

Self check You should understand why these examples are legal or illegal.


Understanding the Big Picture™

  1. What is the purpose of namespaces in C++? In other words, what problem from C was solved by inventing them?
  2. Are there times when namespaces aren't very useful? When?