Game Development by Sean

Unnest C++ Namespaces

Table of Contents

A common complaint by many users of C++ is the pain of nesting namespaces when declaring classes. While future additions to C++ like N4230 will make things much cleaner, most of us will have to deal with C++11 or even C++98 compilers for a while yet.

The problem is that defining a class inside of a namespace requires opening the namespace with braces. This includes declaring an inner namespace. It’s particularly ugly when a class definition contains many lines of code or inner declarations. Example:

namespace foo {
  namespace bar {
    class gaz {
      // 3 levels of nesting
      
      void example() {
        // 4 levels of nesting
      }
      
      // more class definition
    };
  } // bar
} // foo

An alternative approach that avoids the deep visual nesting it to indent namespace contents. This is also considered ugly by many due to the style inconsistency regarding braces and indentation. Example:

namespace foo {
namespace bar {

class gaz
{
  // 1 level of nesting
  
  void example()
  {
    // 2 levels of nesting
  }
  
  // more class definition
};

} // namespace bar
} // namespace foo

Thankfully, there’s a neat trick that allows a class definition to remain outside of the namespace. This trick is fully valid C++98. It still requires declaring nested namespaces but it minimizes the amount of code that must be inside of them. The trick relies on the fact that you can define any previously-declared name using namespace qualifiers. This is often used for functions but rarely for classes. I surmise this is just because many C++ users don’t realize it’s legal. Example:

namespace foo
{
  namespace bar
  {
    class gaz;
  }
}

class foo::bar::gaz
{
  // 1 level of nesting

  inline void example();
  
  // more class definition
};

void foo::bar::gaz::example()
{
  // 1 level of nesting
}

And there we have it. Just like you can separate a function declaration and definition - and the function definition can use namespace qualifiers - you can do the same thing with classes.

This lets you avoid both deep nesting of large blocks of code and inconsistent rules for braces between namespaces and other uses. The namespace nesting is still present, but as the namespace definitions only include forward declarations, they can be kept quite short in most cases.