内联命名空间是类似于 symbol versioning 的库版本控制功能,但纯粹在 C++11 级别(即跨平台)实现,而不是作为特定二进制可执行格式的功能(即特定于平台)。
这是一种机制,库作者可以通过该机制使嵌套命名空间看起来并像其所有声明都在周围的命名空间中一样(内联命名空间可以嵌套,因此“更多嵌套”的名称一直渗透到第一个非内联命名空间,并且看起来和行为就好像它们的声明也在两者之间的任何命名空间中一样)。
例如,考虑vector 的STL 实现。如果我们从 C++ 开始就有内联命名空间,那么在 C++98 中,标题 <vector> 可能看起来像这样:
namespace std {
#if __cplusplus < 1997L // pre-standard C++
inline
#endif
namespace pre_cxx_1997 {
template <class T> __vector_impl; // implementation class
template <class T> // e.g. w/o allocator argument
class vector : __vector_impl<T> { // private inheritance
// ...
};
}
#if __cplusplus >= 1997L // C++98/03 or later
// (ifdef'ed out b/c it probably uses new language
// features that a pre-C++98 compiler would choke on)
# if __cplusplus == 1997L // C++98/03
inline
# endif
namespace cxx_1997 {
// std::vector now has an allocator argument
template <class T, class Alloc=std::allocator<T> >
class vector : pre_cxx_1997::__vector_impl<T> { // the old impl is still good
// ...
};
// and vector<bool> is special:
template <class Alloc=std::allocator<bool> >
class vector<bool> {
// ...
};
};
#endif // C++98/03 or later
} // namespace std
根据__cplusplus 的值,选择一个或另一个vector 实现。如果您的代码库是用 C++98 之前的版本编写的,并且您在升级编译器时发现 vector 的 C++98 版本给您带来了麻烦,那么您所要做的就是找到在您的代码库中引用 std::vector 并将其替换为 std::pre_cxx_1997::vector。
出现下一个标准,STL 供应商只是再次重复该过程,为 std::vector 引入一个新的命名空间,支持 emplace_back(需要 C++11)并内联该命名空间 iff __cplusplus == 201103L。
好的,那我为什么需要一个新的语言功能呢?我已经可以执行以下操作以达到相同的效果,不是吗?
namespace std {
namespace pre_cxx_1997 {
// ...
}
#if __cplusplus < 1997L // pre-standard C++
using namespace pre_cxx_1997;
#endif
#if __cplusplus >= 1997L // C++98/03 or later
// (ifdef'ed out b/c it probably uses new language
// features that a pre-C++98 compiler would choke on)
namespace cxx_1997 {
// ...
};
# if __cplusplus == 1997L // C++98/03
using namespace cxx_1997;
# endif
#endif // C++98/03 or later
} // namespace std
根据__cplusplus 的值,我会得到其中一个实现。
你几乎是正确的。
考虑以下有效的 C++98 用户代码(已经允许在 C++98 中完全特化位于命名空间 std 中的模板):
// I don't trust my STL vendor to do this optimisation, so force these
// specializations myself:
namespace std {
template <>
class vector<MyType> : my_special_vector<MyType> {
// ...
};
template <>
class vector<MyOtherType> : my_special_vector<MyOtherType> {
// ...
};
// ...etc...
} // namespace std
这是完全有效的代码,其中用户为一组类型提供自己的向量实现,而她显然知道比 STL(她的副本)中找到的更有效的实现。
但是:当特化一个模板时,你需要在它被声明的命名空间中这样做。标准说 vector 在命名空间 std 中声明,所以这就是用户所在的位置理所当然地期望专门化该类型。
此代码可与非版本化命名空间 std 或 C++11 内联命名空间功能一起使用,但不适用于使用 using namespace <nested> 的版本控制技巧,因为这会暴露真正命名空间所在的实现细节vector 的定义不是 std 直接定义的。
还有其他漏洞可以用来检测嵌套命名空间(请参阅下面的 cmets),但内联命名空间会将它们全部塞住。这就是它的全部。对未来非常有用,但 AFAIK 标准并没有为它自己的标准库规定内联命名空间名称(不过我很想被证明是错误的),所以它只能用于第三方库,而不是标准本身(除非编译器供应商同意命名方案)。