===== 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.