On page 7, he writes "One might think that a more C++-ish way of hoisting a
facility into two namespaces would be to use
a using-declaration
. One would be almost right."
It does seem that using
would be a good way to separate the
actual implementation from the namespace that we want other code to
interact with. But as Herb notes, the problem with this is that we can
only specialize a template in its actual namespace, not a namespace it has
been imported into. Also, argument-dependent lookup breaks down if library
components are split across multiple namespaces.
inline
keyword in
a namespace-definition
to specify that members of the
namespace can be defined and specialized as though they actually belong to
the enclosing namespace. This is referred to as namespace association
because of its effects on argument-dependent lookup.
This extension has been implemented in the GNU and EDG compilers for several years now (expressed with a special using-directive, rather than a change to the namespace definition itself), and is getting a fair amount of use.
The syntax in this proposal has changed based on suggestions from other members of the committee, notably Daveed Vandevoorde.
For instance:
namespace Lib { inline namespace Lib_1 { template <typename T> class A; } template <typename T> void g(T); } ... struct MyClass { ... }; namespace Lib { template<> class A<MyClass> { ... }; } int main() { Lib::A<MyClass> a; g(a); // ok, Lib is an associated namespace of A }
Also add new paragraphs:original-namespace-definition: inlineopt namespace identifier { namespace-body } extension-namespace-definition: inlineopt namespace original-namespace-name { namespace-body } unnamed-namespace-definition: inlineopt namespace { namespace-body }
If the optional initial inline keyword appears in a namespace-definition for a particular namespace, that namespace is declared to be an inline namespace. The inline keyword may be used on an extension-namespace-definition only if it was previously used on the original-namespace-definition for that namespace.
Members of an inline namespace can be used in most respects as though they were members of the enclosing namespace. Specifically, the inline namespace and its enclosing namespace are considered to be associated namespaces ([basic.lookup.argdep]) of one another, and a using directive ([namespace.udir]) which names the inline namespace is implicitly inserted into the enclosing namespace. Furthermore, each member of the inline namespace can subsequently be explicitly instantiated ([temp.explicit]) or explicitly specialized ([temp.expl.spec]) as though it were a member of the enclosing namespace. Finally, looking up a name in the enclosing namespace via explicit qualification ([namespace.qual]) will include members of the inline namespace brought in by the using directive even if there are declarations of that name in the enclosing namespace.
These properties are transitive: if a namespace N contains an inline namespace M, which in turn contains an inline namespace O, then the members of O can be used as though they were members of M or N. The set of namespaces consisting of the innermost non-inline namespace enclosing an inline namespace O, together with any intervening inline namespaces, is the enclosing namespace set of O.
If an associated namespace is an inline namespace ([namespace.def]), its enclosing namespace is also included in the set. If an associated namespace contains inline namespaces, those inline namespaces are also included in the set. In addition, if the argument is the name or address of a set of overloaded functions and/or function templates...
An explicit instantiation shall appear in an enclosing namespace of its template. If the name declared in the explicit instantiation is an unqualified name, the explicit instantiation shall appear in the namespace where its template is declared or, if that namespace is inline ([namespace.def]), any namespace from its enclosing namespace set.
-2- An explicit specialization shall be declared in
the nearest enclosing namespace of the template namespace of
which the template is a member, or, for member templates, in the
namespace of which the enclosing class or enclosing class template is a
member, or, if that namespace is inline ([namespace.def]), any
namespace from its enclosing namespace set. An explicit
specialization of a member template, member function, member class or
static data member of a class template shall be declared in the namespace
of which the class template is a member. Such a declaration may also
be a definition. If the declaration is not a definition, the
specialization may be defined later in the namespace in which the
explicit specialization was declared, or in a namespace that encloses the
one in which the explicit specialization was declared.
When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers (or of an inline namespace within that scope [namespace.def]), and the member shall not have been introduced by a using-declaration in the scope of the class or namespace nominated by the nested-name-specifier of the declarator-id.
A program shall not declare namespace std to be an inline namespace ([namespace.def]).
Herb Sutter, Namespaces and Library Versioning, N1344