现代C++编程实战:132个核心技巧示例(原书第2版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.11.3 工作原理

当函数在编译单元中被声明时,它具有外部链接属性。这意味着来自两个不同编译单元的两个具有相同名称的函数将产生链接错误,因为不可能有两个具有相同名称的符号。在C语言中,解决这个问题的方法是,将函数或变量声明为静态的,并将其链接从外部更改为内部。在这种情况下,它的名称不再被导出到编译单元之外,避免了链接问题。

在C++中,一种合适的解决方法是使用匿名命名空间。当像前面那样定义一个命名空间时,编译器会把它转换成如下形式:

首先,它声明了一个具有唯一名称的命名空间(名称是什么以及如何生成该名称是编译器实现的细节,我们无须关注),此时命名空间还是空的,这一行代码的目的是构建命名空间。其次,使用using关键字在当前命名空间引入_unique_name_命名空间中的所有内容。最后,名称由编译器生成的命名空间的定义与原始源代码中的一样(当时命名空间是匿名的)。

通过在匿名命名空间中定义编译单元局部print()函数,它们仅具有本地可见性,但它们的外部链接不再产生链接错误,因为它们现在具有外部唯一名称。

匿名命名空间还可以用于更复杂的情形,比如模板。一方面,在C++11之前,模板非类型实参不能是具有内部链接的名称,因此不可能使用静态变量。另外,匿名命名空间中的符号具有外部链接,可以用作模板实参。虽然C++11中取消了模板非类型实参的链接限制,但它仍然存在于最新版本的VC++编译器中。该问题如下所示:

在此代码片段中,t1变量的声明导致了一个编译错误,因为非类型实参表达式Size1有内部链接。t2变量的声明是正确的,因为Size2有外部链接(注意,用Clang和GCC编译此代码片段不会产生错误)。