Why and how should I use namespaces in C++?

One reason that’s often overlooked is that simply by changing a single line of code to select one namespaces over another you can select an alternative set of functions/variables/types/constants – such as another version of a protocol, or single-threaded versus multi-threaded support, OS support for platform X or Y – compile and run. The same kind of effect might be achieved by including a header with different declarations, or with #defines and #ifdefs, but that crudely affects the entire translation unit and if linking different versions you can get undefined behaviour. With namespaces, you can make selections via using namespace that only apply within the active namespace, or do so via a namespace alias so they only apply where that alias is used, but they’re actually resolved to distinct linker symbols so can be combined without undefined behaviour. This can be used in a way similar to template policies, but the effect is more implicit, automatic and pervasive – a very powerful language feature.


UPDATE: addressing marcv81’s comment…

Why not use an interface with two implementations?

“interface + implementations” is conceptually what choosing a namespace to alias above is doing, but if you mean specifically runtime polymorphism and virtual dispatch:

  • the resultant library or executable doesn’t need to contain all implementations and constantly direct calls to the selected one at runtime

  • as one implementation’s incorporated the compiler can use myriad optimisations including inlining, dead code elimination, and constants differing between the “implementations” can be used for e.g. sizes of arrays – allowing automatic memory allocation instead of slower dynamic allocation

  • different namespaces have to support the same semantics of usage, but aren’t bound to support the exact same set of function signatures as is the case for virtual dispatch

  • with namespaces you can supply custom non-member functions and templates: that’s impossible with virtual dispatch (and non-member functions help with symmetric operator overloading – e.g. supporting 22 + my_type as well as my_type + 22)

  • different namespaces can specify different types to be used for certain purposes (e.g. a hash function might return a 32 bit value in one namespace, but a 64 bit value in another), but a virtual interface needs to have unifying static types, which means clumsy and high-overhead indirection like boost::any or boost::variant or a worst case selection where high-order bits are sometimes meaningless

  • virtual dispatch often involves compromises between fat interfaces and clumsy error handling: with namespaces there’s the option to simply not provide functionality in namespaces where it makes no sense, giving a compile-time enforcement of necessary client porting effort

Leave a Comment