Mechanism for expressing logical grouping – various properties of C++ namespaces, including:
inline
namespacesLinks:
namespace N { // [named] namespace definition bool f(); // declaration of f() bool f(int); // declaration of f(int) bool g() { return true; } // declaration/definition of g() }; void N::f() { return false; } // definition using namespace N; // using directive using N::f; // using declaration namespace { // unnamed namespace definition ... }; namespace ATT = American_Telephone_and_Telegraph; // namespace alias
Also, namespace identifier is “… either a previously unused identifier, in which case this is original-namespace-definition or the name of a namespace, in which case this is extension-namespace-definition.”
You can extend a namespace by adding names to it from multiple namespace declarations (possibly scattered across multiple header files) – useful for converting older programs to use namespaces:
namespace A { int f(); } namespace A { int g(); }
std
namespace is undefined.NOTE: “A using-declaration adds a name to a local scope (also, “introduces a synonym into a scope”). A using-directive does not; it simply renders names accessible in the scope in which they were declared.”
This means that a using declaration will override a using definition; see “Composition and selection.”
Read this carefully.
“makes the symbol name from the namespace ns_name accessible for unqualified lookup as if declared in the same class scope, block scope, or namespace as where this using-declaration appears.”
using N::f;
NOTE: When used for an overloaded name, a using-declaration applies to all the overloaded versions:
namespace N { void f(int); void f(string); }; void g() { using N::f; f(789); // N::f(int) f("Bruce"); // N::f(string) }
Useful for introducing base class members into derived class definitions.
cppreference.com link here.
“From the point of view of unqualified name lookup of any name after a using-directive and until the end of the scope in which it appears, every name from ns_name is visible as if it were declared in the nearest enclosing namespace which contains both the using-directive and ns_name.”
using namespace N;
Keep their use inside scopes (functions) to avoid massive side effects. Even worse, don't include them in global scopes in header files.
namespace His_lib { class String { ... }; template<typename T> class Vector { ... }; // ... namespace Her_lib { template<typename T> class Vector { ... }; class String { ../ }; // ... } // Does the order of the following matter? namespace My_lib { using namespace His_lib; // everything from His_lib using namespace Her_lib; // everything from Her_lib using His_lib::String; // resolve potential clash in favor of His_lib using Her_lib::Vector; // resolve potential clash in favor of Her_lib }
IMPORTANT: When looking into a namespace, names explicitly declared there (including names declared by using-declarations) take priority over names made accessible in another scope by a using-directive (see also §14.4.1). Consequently, a user of My_lib
will see the name clashes for String
and Vector
resolved in favor of His_lib::String
and Her_lib::Vector
.
Can also rename for clarity:
namespace Lib2 { using namespace His_lib; // everything from His_lib using namespace Her_lib; // everything from Her_lib using His_lib::String; // resolve potential clash in favor of His_lib using Her_lib::Vector; // resolve potential clash in favor of Her_lib using Her_string = Her_lib::String; // rename template<typename T> using His_vec = His_lib::Vector<T>; // rename ... }
void h(); namespace X { void g(); // ... namespace Y { void f(); void ff(); // ... } } void X::Y::ff() { f(); g(); h(); // all fine } void X::g() { f(); // error: no f() in X Y::f(); // OK } void h() { f(); // error: no global f() Y::f(); // error: no global Y X::f(); // error: no f() in X X::Y::f(); // OK }
NOTE: C++17 allows namespace A::B::C { … }
.
namespace American_Telephone_and_Telegraph { // too long // ... } American_Telephone_and_Telegraph::String s3 = "Grieg"; American_Telephone_and_Telegraph::String s4 = "Nielsen"; // use namespace alias to shorten names namespace ATT = American_Telephone_and_Telegraph; ATT::String s3 = "Grieg"; ATT::String s4 = "Nielsen";
Declarations inside an inline namespace will be visible in its enclosing namespace.
Supports versioning:
namespace Lib inline namespace V2_0 { ... V2.0 declarations ... } namespace V1_0 { ... V1.0 declarations ... } }
Or create your own namespace based on that feature:
// file V99.h: inline namespace V99 { void f(int); // does something better than the V98 version void f(double); // new feature // ... } // file V98.h: namespace V98 { void f(int); // does something // ... } // file Mine.h: namespace Mine { #include "V99.h" #include "V98.h" }
We here have a namespace Mine
with both the latest release (V99
) and the previous one (V98
). If you want to be specific, you can:
#include "Mine.h" using namespace Mine; // ... V98::f(1); // old version V99::f(1); // new version f(1); // default version (in this case, V99)
One last weird variation, where you can choose your own default:
namespace MyDefault { inline #include "V3_0.h" // the new default #include "V3_2.h" #include "V2_4_2.h" }
“I do not recommend such intricate use of header files unless it is really necessary. The example above repeatedly violates the rules against including into a nonlocal scope and against having a syntactic construct span file boundaries (the use of inline); see §15.2.2. Sadly, I have seen worse.”
Its members have potential scope from their point of declaration to the end of the translation unit, and have internal linkage. The aim is to preserve locality of code rather than to present an interface to users.
#include "header.h" namespace { int a; void f() {...} int g() {...} }
An unnamed namespace has an implied using-directive.
“Unnamed namespaces in different translation units are different. As desired, there is no way of naming a member of an unnamed namespace from another translation unit.”
Coming soon … see here. Particularly useful with:
Basically: