购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.12 使用内联命名空间进行符号版本控制

C++11标准引入了一种新的命名空间类型,称为 内联命名空间 ,它本质上是一种机制,使得来自嵌套命名空间的声明就像是周围命名空间的一部分。使用inline关键字声明内联命名空间(匿名命名空间也可以内联)。这是库版本控制的一个有用特性,在本节中,我们将介绍如何使用内联命名空间来对符号进行版本控制。从这一节中,你将了解如何使用内联命名空间和条件编译来管理源代码版本。

1.12.1 准备工作

在本节中,我们将讨论命名空间和嵌套命名空间、模板和模板特化,以及使用预处理器宏的条件编译。要学习本节内容,需要熟悉这些概念。

1.12.2 使用方式

要提供库的多个版本并让用户决定使用哪个版本,请执行以下操作:

❍ 在命名空间内定义库的内容。

❍ 在内联命名空间中定义库的每个版本。

❍ 使用预处理器宏和#if指令来启用特定版本的库。

下面的例子展示了一个库,它有两个版本可供客户端使用:

1.12.3 工作原理

内联命名空间的成员被视为周围命名空间的成员,这样的成员可以偏特化、显式实例化或显式特化。这是一个传递属性,这意味着如果命名空间A包含内联命名空间B,而B又包含内联命名空间C,那么C的成员是B和A的成员,而B的成员是A的成员。

为了更好地理解内联命名空间的作用,我们考虑这样一种情况:开发一个库,它会随着时间的推移从第一个版本发展到第二个版本(以及进一步发展),这个库在名为modernlib的命名空间下定义了所有的类型和函数。在第一个版本中,这个库看起来像这样:

库的客户端可以执行以下调用并返回值1:

然而,客户端可能决定像下面这样特化模板函数test():

在本例中,y的值不再是1,而是42,因为调用了用户特化的函数。

到目前为止,一切运行正常,但是作为库开发人员,你决定创建库的第二个版本,但仍同时发布第一个和第二个版本,并通过宏让用户决定选择使用哪个版本。在第二个版本中,你提供了test()函数的新实现,它不再返回1,而是返回2。为了能够同时提供第一个和第二个实现,你将它们放在名为version_1和version_2的嵌套命名空间中,并使用预处理器宏条件编译库:

出乎意料,客户端代码会崩溃,不管它使用的是库的第一个版本还是第二个版本。这是因为test函数现在在一个嵌套的命名空间中,foo的特化在modernlib命名空间中完成,但它实际上应该在modernlib::version_1或modernlib::version_2中实现。这是因为模板特化应在声明模板的同一命名空间中实现。

在这种情况下,客户端需要更改代码,如下所示:

这是一个问题,因为库暴露了实现细节,客户端需要了解这些细节以便进行模板特化。1.12.2节讲述了这些内部细节如何用内联命名空间隐藏。有了modernlib库的这个定义,在modernlib命名空间中客户端代码定义的特化test函数就不再会被破坏,因为当模板特化完成时,version_1::test()或version_2::test()(取决于客户端用的版本)都是外围modernlib命名空间的一部分。实现细节现在对客户端是隐藏的,客户端只能看到外围命名空间modernlib。

但是,你应该记住,命名空间std是为标准保留的,永远不应该内联。另外,如果命名空间在第一个定义中不是内联的,那么它就不应该被定义为内联的。

1.12.4 延伸阅读

❍ 阅读1.11节,以了解匿名命名空间及匿名命名空间的作用。

❍ 阅读4.1节,以了解执行条件编译的各种选项。 jDCwNm1wwOJcLIvxOHF905qhNkwvwBBy1mNu12x01TCTlyKFYSHNPM1YFSX9CYik

点击中间区域
呼出菜单
上一章
目录
下一章
×