C++ Namespaces
A namespace is a named block of code within which names have local scope, that is, they do not add to or clash with the enclosing or global scope. Namespaces delimit areas and allow for modularity.
You declare a namespace line this:
namespace <namespace> { ... }
What you type within the curly brackets has local scope and does not clash with its enclosing scope.
Scope resolution
You can refer to a same-named global variable within a namespace by prefixing it with "::". In the following code global variable x, not its local namesake, is used to initialize another. Alternatively, you can invoke an object in another namespace by prefixing its name with its namespace.
char x = 'x'; namespace scratch { char x = 'y'; char global_x = ::x; } if(scratch::global_x == x) ...;
using
Declarations in Namespaces
Last, you may import either a whole namespace into the current one by typing:
using <namespace>;
or just one name from a namespace:
using <namespace>::<name>;
Namespaces Are Open
A namespace is open; that is, you can add names to it from several separate namespace declarations. For example:
namespace A { int f(); // now A has member f() } namespace A { int g(); // now A has two members, f() and g() }
That way, the members of a namespace need not be placed contiguously in a single file. This can be important when converting older programs to use namespaces.
Inline Namespaces (inline namespace my_namespace
)
inline namespaces. Inline namespaces aren't really namespaces: Everything declared inside of them are also part of the parent namespace.
Introduced in C++11.
An example:
namespace foo // normal namespace { void foo_func(); // function inside normal namespace } inline namespace bar // inline namespace { void bar_func(); // function inside inline namespace } foo::foo_func(); // okay bar::bar_func(); // also okay foo_func(); // error, no such function bar_func(); // okay, inline namespace!
Useless?
API Versioning
Suppose you have written a library with some utility class foo:
namespace my_library { class foo { … }; }
But you're not quite happy with foo, so in a future version, you've improved it substantially. Sadly, the new foo is not completely backwards compatible: Some users have to use the old version.
So to ease the transition, you still provide both:
namespace my_library { namespace v1 { // old foo class foo { … }; } inline namespace v2 { // new, improved foo class foo { … }; } // note: no `foo` in `my_library` directly }
Most users just continue to use my_library::foo
and will silently get the v2 version. Users that can't use v2 just need to switch to my_library::v1::foo
instead. This can be a transition that is a lot easier to do.
// on update it will get the shiny new v2 version my_library::foo f; // but maybe I don't want it, just change the namespace my_library::v1::foo f;
Koenig Lookup
Note: Koenig Lookup is sometimes called argument dependent lookup.
Overloaded functions may be called without qualifying the function name with the namespace. Using a process called Koenig lookup the C++ compiler examines the argument type and looks for overloaded functions in the namespace of the argument type.
The following example illustrates Koenig lookup. Consider the case of someone using graph classes that are supplied by two different graph libraries. Each library has its own namespace, inside of which is defined a graph
class and a num_vertices()
function.
namespace lib_jack { class graph { /* . . . */ }; int num vertices(const graph&) { /* . . . */ } } namespace lib_jill { class graph { /* . . . */ }; int num vertices(const graph&) { /* . . . */ } }
Suppose the user wants to apply some generic graph algorithm, say boost::pail()
, to both of these graph types.
int main() { lib_jack::graph g1; boost::pail(g1); lib_jill::graph g2; boost::pail(g2); }
Inside of the boost::pail()
there is a call to num_vertices()
. The desired behavior in this situation is that if a graph from lib_jack is used, then lib_jack::num vertices()
gets called, but if the graph from lib_jill is used, then lib_jill::num_vertices()
gets called. Koenig lookup is the C++ language feature that provides this behavior. Provided the function call is not qualified with a namespace, the C++ compiler will search the namespace of the arguments to find the correct function to call.