Namespaces were introduced into the C++ standard in 1995, and they are usually defined like this:
A namespace defines a new scope. Namespaces provide a way to avoid name collisions.
Although namespaces are used extensively in recent C++ code, most older code does not use this facility.
After exploring the source code of many C++ projects, here are some common reasons why namespaces are used in these projects.
1- Avoid name collisions.
In this case, their use primarily benefits the compiler; it does not provide any additional value to the developer in terms of code readability or maintainability.
2- Modularize the code
Modern C++ libraries use namespaces extensively to modularize their code base, and they use the “Namespace-by-feature” approach. Namespace-by-feature uses namespaces to reflect the feature set. It places all items related to a single feature (and only that feature) into a single namespace. This results in namespaces with high cohesion and high modularity, and with minimal coupling between namespaces. Items that work closely together are placed next to each other.
Boost is a great example of grouping by feature; it contains thousands of namespaces, each used to group a specific feature.
3- Anonymous namespace.
An unnamed namespace avoids the need for global static variables. The anonymous namespace you create is accessible only within the file in which it is defined.
4- Workaround for the enum issue.
“Traditional” enums in C++ export their enumerators into the surrounding scope, which can lead to name collisions if two different enums in the same scope define enumerators with the same name.
In a large project, there is no guarantee that two distinct enums will not use the same name. This issue was resolved in C++11 with enum class, which implicitly scopes the enum values within the enum’s name.
Before C++11, a common workaround was to declare an enum inside a namespace. For example, instead of declaring an enum like this:
enum status{
status_ok,
status_error
};it could be declared inside a namespace:
namespace status{
enum status{
ok,
error
};
}Many C++ projects use this trick; for example, the Unreal Engine source code uses this technique widely.
5- Hiding details by convention
For template libraries whose code is implemented in header files, it is useful to indicate to library users that certain types should not be used directly because they are implementation details. In C#, the “internal” keyword serves this purpose, but in C++ there is no way to hide public types from library users.
A common idiom in modern C++, pioneered by the developers of the Boost libraries, is to separate symbols that form part of the implementation of your module (that is, don’t form part of the public API) but that have to be publicly available into a separate sub-namespace, by convention named detail.
For example, the Boost.Math documentation specifies that:
Functions not intended for use by applications are in boost::math::detail.The inline namespaces introduced in C++11 provide two additional possibilities:
When an inline namespace is defined, a using directive is implicitly inserted into its enclosing namespace. While looking up a qualified name through the enclosing namespace, members of the inline namespace are brought in and found by the implicit using directive, even if that name is declared in the enclosing namespace.
For example, if you compile the following code with USE_INLINE_B defined, the output of the resulting executable is 1; otherwise, the output is 2.
namespace A {
#if USE_INLINE_B
inline
#endif
namespace B {
int foo(bool) { return 1; }
}
int foo(int) { return 2; }
}
int main(void) {
return A::foo(true);
}Here are two additional uses for inline namespaces, as explained in this document.
6- Using inline namespace definitions in explicit instantiation and specialization
You can explicitly instantiate or specialize each member of an inline namespace as if it were a member of its enclosing namespace. Name lookup for the primary template of an explicit instantiation or specialization in a namespace, for example M, considers the inline namespaces whose enclosing namespace set includes M. For example:
namespace L {
inline namespace M {
template <typename T> class C;
}
template <typename T> void f(T) { /*...*/ };
}
struct X { /*...*/ };
namespace L {
template<> class C<X> { /*...*/ }; //template specialization
}
int main()
{
L::C<X> r;
f(r); // fine, L is an associated namespace of C
}In this example,
Mis an inline namespace of its enclosing namespace
L, class
Cis a member of inline namespace
M, so
Lis an associated namespace of class
C.
The following rules apply when you use inline namespace definitions in explicit instantiation and specialization:
- An explicit instantiation must be in an enclosing namespace of the primary template if the template name is qualified; otherwise, it must be in the nearest enclosing namespace of the primary template or a namespace in the enclosing namespace set.
- An explicit specialization declaration must first be declared in the namespace scope of the nearest enclosing namespace of the primary template, or a namespace in the enclosing namespace set. If the declaration is not a definition, it may be defined later in any enclosing namespace.
7- Using inline namespace definitions in library versioning
With inline namespace definitions, you can provide a common source interface for a library with several implementations, and a user of the library can choose one implementation to be associated with the common interface. The following example demonstrates the use of inline namespace in library versioning with explicit specialization.
//foo.h
#ifndef SOME_LIBRARY_FOO_H_
#define SOME_LIBRARY_FOO_H_
namespace SomeLibrary
{
#ifdef SOME_LIBRARY_USE_VERSION_2_
inline namespace version_2 { }
#else
inline namespace version_1 { }
#endif
namespace version_1 {
template <typename T> int foo(T a) {return 1;}
}
namespace version_2 {
template <typename T> int foo(T a) {return 2;}
}
}
#endif
//myFooCaller.C
#include <Foo.h>
#include <iostream>
struct MyIntWrapper { int x;};
//Specialize SomeLibrary::foo()
//Should specialize the correct version of foo()
namespace SomeLibrary {
template <> int foo(MyIntWrapper a) { return a.x;}
}
int main(void) {
using namespace SomeLibrary;
MyIntWrapper intWrap = { 4 };
std::cout << foo(intWrap) + foo(1.0) << std::endl;
}If you compile this example with SOME_LIBRARY_USE_VERSION_2_ defined, the output of the resulting executable is 6; otherwise, the output is 5. If the function call,
foo(intWrap), is qualified with one of the inline namespaces, then you need to ensure that the explicit specialization is effective.
