===== Overview =====
Mechanism for expressing logical grouping -- various properties of C++ namespaces, including:
* terminology (declarations, definitions)
* ''inline'' namespaces
* unnamed namespaces
* nested namespaces
* namespace aliases
* extensibility
* namespaces and overloading
* argument dependent lookup (ADL)
Links:
* [[http://en.cppreference.com/w/cpp/language/namespace|cppreference.com]]
===== Questions =====
* "A using-declaration adds a name to a local scope. A using-directive does not; it simply renders names accessible in the scope in which they were declared." ????? What does this mean? (See below.)
* Namespace member clashes only an issue when you try to use them?
===== Terminology =====
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//."
===== Extensibility (namespaces are "open") =====
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();
}
* You can extend a namespace using additional definitions based on the same name (to catch accidental misspellings).
* You cannot declare a new member of a namespace outside a namespace definition using the qualifier syntax.
* Extending the ''std'' namespace is undefined.
* A namespace alias cannot be used to re-open a namespace.
===== using (declarations and definitions) =====
==== Distinction ====
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."
==== using-Declarations ====
Read [[http://en.cppreference.com/w/cpp/language/namespace#Using-declarations|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.
==== using-Directives ====
cppreference.com link [[http://en.cppreference.com/w/cpp/language/namespace#Using-directives|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.
==== Tradeoffs ====
* If some qualification is really common for several names, use a using-directive for that namespace.
* If some qualification is common for a particular name from a namespace, use a using-de- claration for that name.
* If a qualification for a name is uncommon, use explicit qualification to make it clear from where the name comes.
* Don’t use explicit qualification for names in the same namespace as the user.
===== Composition and selection =====
namespace His_lib {
class String { ... };
template
class Vector { ... };
// ...
namespace Her_lib {
template
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
using His_vec = His_lib::Vector; // rename
...
}
===== Nested namespaces =====
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 aliases =====
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";
* Aliases can be used to refer to nested namespaces.
* A namespace alias cannot be used to re-open a namespace.
===== Inline namespaces (new in C++11) =====
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."
===== Unnamed namespaces =====
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."
===== Argument dependent lookup (ADL) =====
Coming soon ... see [[http://en.cppreference.com/w/cpp/language/adl|here]]. Particularly useful with:
* operator operands
* template arguments
Basically:
* If an argument is a class member, the associated namespaces are the class itself (including its base classes) and the class’s enclosing namespaces.
* If an argument is a member of a namespace, the associated namespaces are the enclosing namespaces.
* If an argument is a built-in type, there are no associated namespaces.