c++标准委员会于2003年首次提出,最终接受嵌套名称空间的定义如下:
namespace A::B::C
{
...
}
即等于:
namespace A
{
namespace B
{
namespace C
{
...
}
}
}
注意,嵌套不支持内联命名空间。这仅仅是因为内联应用于最后一个名称空间还是应用于所有名称空间并不明显(两者都同样有用)。
这里简单介绍下inline namespace
C++11新标准引入了一种新的嵌套命名空间,称为内联命名空间(inline namespace)。和普通的嵌套命名空间不同,内联命名空间中的名字可以被外层命名空间直接使用。也就是说,我们无须在内联命名空间的名字前添加表示该命名空间的前缀,通过外层命名空间的名字就可以直接访问它。定义内联命名空间的方式是在关键字namespace前添加关键字inline。关键字inline必须出现在命名空间第一次定义的地方,后续再打开命名空间的时候可以写inline,也可以不写。当应用程序的代码在一次发布和另一次发布之间发生了改变时,常常会用到内联命名空间。
这个特性对于代码版本升级且需保留旧版本代码的情况来说实在是太有用了。
namespace work {
namespace edition1 {
/*初始版本代码*/
};
inline namespace edition2 {
/*新版本代码*/
};
};
当我们更新代码以及新代码出现故障紧急回撤版本时,只需要增删inline即可,只要保证接口不变,则可以实现无缝更换。
列子:
#include <stdio.h>
namespace Outer
{
inline namespace V2
{
void foo()
{
printf("V2::foo()\n");
}
}
namespace V1
{
void foo()
{
printf("V1::foo()\n");
}
}
}
int main()
{
Outer::V1::foo();
Outer::V2::foo();
Outer::foo();
}
第28行,调用Outer中的默认名字空间V2的foo().
用途:新版本的升级测试。foo升级到V2版本。如果升级不理想,可以把V1改成inline,V2改成非inline。这将就降级回旧版的foo函数。
从前是用宏#ifdef V2 ...#endif之类的技术。使用inline namespace带来一个明显的好处是:可以同时使用新版本的foo和旧版本的foo(正如第26行所示)。
内联命名空间是在其原初命名空间定义中使用了可选的关键词 inline
的命名空间。
许多情况下(列于下方),内联命名空间的成员都被当做如同它们是其外围命名空间的成员一样。这项性质是传递性的:若命名空间 N 包含内联命名空间 M,它又继而包含内联命名空间 O,则 O 的成员能按如同它们是 M 或 N 的成员一样使用。
- 在外围命名空间中,隐含地插入了一条指名内联命名空间的 using 指令(类似于无名命名空间的隐式 using 指令)
- 实参依赖查找中,当将命名空间添加到关联命名空间集合时,亦添加其内联命名空间,而当添加内联命名空间到关联命名空间列表时,亦添加其外围命名空间。
- 内联命名空间的每个成员,都能按照如同它是外围命名空间的成员一样,进行部分特化、显式实例化或显式特化。
- 检验外围命名空间的有限定名字查找,将包含来自其各个内联命名空间的名称,即使同一名称已存在于外围命名空间也是如此。
再来看一个例子:
namespace inline_test
{
inline namespace inline_namespace1
{
class Inline1
{
public:
int iv;
};
}
/* 关键字inline必须出现在命名空间第一次定义的地方,后续再打开命名空间的时候可以写inline,也可以不写 */
namespace inline_namespace1
{
class Inline2
{
public:
double dv;
};
inline namespace inline_namespace1_1
{
int id;
}
}
void test_inline_namespace()
{
Inline1 in1;
in1.iv = 5;
Inline2 in2;
in2.dv = 3.14;
id = 100;
std::cout << in1.iv << ", " << in2.dv << ", " << id << std::endl;
}
}
void test_inline_namespace2()
{
inline_test::Inline1 in1;
in1.iv = 5 * 2;
inline_test::Inline2 in2;
in2.dv = 3.14 * 2;
inline_test::id = 100 * 2;
std::cout << in1.iv << ", " << in2.dv << ", " << inline_test::id << std::endl;
}
int main()
{
inline_test::test_inline_namespace();
test_inline_namespace2();
inline_test::id = 9999;
return 0;
}
上述代码中test_inline_namespace处在linline_namespace1的外层,所以可以直接使用Inline1和Inline2。test_inline_namespace2处在更外层,这时也只是需要使用外层命名空间inline_test前缀即可。而对于变量id,若命名空间inline_test 包含内联命名空间inline_namespace1,inline_namespace1又继而包含内联命名空间inline_namespace1_1,则inline_namespace1_1 的成员能按如同它们是 inline_test 或 inline_namespace1N 的成员一样使用。
结果如下: