Inline namespaces are a library versioning feature akin to symbol versioning, but implemented purely at the C++11 level (ie. cross-platform) instead of being a feature of a specific binary executable format (ie. platform-specific).
It is a mechanism by which a library author can make a nested namespace look and act as if all its declarations were in the surrounding namespace (inline namespaces can be nested, so "more-nested" names percolate up all the way to the first non-inline namespace and look and act as if their declarations were in any of the namespaces in between, too).
As an example, consider the STL implementation of vector
. If we had inline namespaces from the beginning of C++, then in C++98 the header <vector>
might have looked like this:
namespace std {
#if __cplusplus < 1997L
inline
#endif
namespace pre_cxx_1997 {
template <class T> __vector_impl;
template <class T> // e.g. w/o allocator argument
class vector : __vector_impl<T> {
};
}
#if __cplusplus >= 1997L
# if __cplusplus == 1997L
inline
# endif
namespace cxx_1997 {
template <class T, class Alloc=std::allocator<T> >
class vector : pre_cxx_1997::__vector_impl<T> {
};
template <class Alloc=std::allocator<bool> >
class vector<bool> {
};
};
#endif
}
Depending on the value of __cplusplus
, either one or the other vector
implementation is chosen. If your codebase was written in pre-C++98 times, and you find that the C++98 version of vector
is causing trouble for you when you upgrade your compiler, "all" you have to do is to find the references to std::vector
in your codebase and replace them by std::pre_cxx_1997::vector
.
Come the next standard, and the STL vendor just repeats the procedure again, introducing a new namespace for std::vector
with emplace_back
support (which requires C++11) and inlining that one iff __cplusplus == 201103L
.
OK, so why do I need a new language feature for this? I can already do the following to have the same effect, no?
namespace std {
namespace pre_cxx_1997 {
}
#if __cplusplus < 1997L
using namespace pre_cxx_1997;
#endif
#if __cplusplus >= 1997L
namespace cxx_1997 {
};
# if __cplusplus == 1997L
using namespace cxx_1997;
# endif
#endif
}
Depending on the value of __cplusplus
, I get either one or the other of the implementations.
And you'd be almost correct.
Consider the following valid C++98 user code (it was permitted to fully specialize templates that live in namespace std
in C++98 already):
namespace std {
template <>
class vector<MyType> : my_special_vector<MyType> {
};
template <>
class vector<MyOtherType> : my_special_vector<MyOtherType> {
};
}
This is perfectly valid code where the user supplies its own implementation of a vector for a set of type where she apparently knows a more efficient implementation than the one found in (her copy of) the STL.
But: When specializing a template, you need to do so in the namespace it was declared in. The Standard says that vector
is declared in namespace std
, so that's where the user rightfully expects to specialize the type.
This code works with a non-versioned namespace std
, or with the C++11 inline namespace feature, but not with the versioning trick that used using namespace <nested>
, because that exposes the implementation detail that the true namespace in which vector
was defined was not std
directly.
There are other holes by which you could detect the nested namespace (see comments below), but inline namespaces plug them all. And that's all there is to it. Immensely useful for the future, but AFAIK the Standard doesn't prescribe inline namespace names for its own standard library (I'd love to be proven wrong on this, though), so it can only be used for third-party libraries, not the standard itself (unless the compiler vendors agree on a naming scheme).