在具有外部链接的匿名命名空间中声明的实体的示例
Example of entity declared in a anonymous namespace that has external linkage
给定§3.5/4中的以下语句(强调mine)和§7.3.1.1/1中的注释[94],我希望有一个在具有外部链接的未命名命名空间中声明的实体的示例。
§3.5/4
未命名的命名空间或直接或间接声明的命名空间在未命名的命名空间中具有内部链接。所有其他命名空间具有外部链接名称空间作用域尚未上面给定的内部链接与封闭的链接相同命名空间,如果它是的名称
- 变量;或
- 函数;或
- 命名类(第9条),或在typedef声明中定义的未命名类,在该声明中该类具有用于链接的typedef名称目的(7.1.3);或
- 命名枚举(7.2),或在typedef声明中定义的未命名枚举,其中枚举具有的typedef名称链接目的(7.1.3);或
- 属于具有链接的枚举的枚举器;或
- 模板
§7.3.1.1/1注释[94]:
尽管未命名名称空间中的实体可能具有外部链接,他们实际上是由他们翻译的唯一名称限定的单位,因此从任何其他翻译单位都看不到。
您看到的是标准中的一个缺陷。
使未命名名称空间成员具有内部链接的更改发生在2010年11月C++11标准化过程的相当晚的时候(CWG第1113期)。因此,标准中的许多地方需要更改,但没有。其中之一就是你引用的脚注。
CWG第1603期目前处于"准备就绪"状态(内容如下:该决议可能会在下一次委员会会议上通过),将解决这一问题以及与未命名命名空间成员的内部链接相关的其他一些问题。
这是一个很好的问题,因为它很难演示。我们可以利用C++标准中的其他规则来表明匿名命名空间中的变量可以具有外部链接。
对具有外部链接的int*进行模板化将成功,而对具有内部链接的int*进行模板化则将失败。
#include <iostream>
namespace {
// not externally linked, won't compile
// const int i = 5;
// external linkage, compiles
extern int i;
int i = 5;
}
template<int* int_ptr>
struct temp_on_extern_linked_int {
temp_on_extern_linked_int() {
std::cout << *int_ptr << std::endl;
}
};
int main() {
temp_on_extern_linked_int<&i>();
}
如图所示,程序编译并运行。
$ g++-4.8 main.cpp -o main
$ ./main
5
取消对i
的其他定义的注释会导致编译失败。
$ g++-4.8 main.cpp -o main
main.cpp: In function 'int main()':
main.cpp:17:30: error: '& {anonymous}::i' is not a valid template argument of
type 'int*' because '{anonymous}::i' does not have external linkage
temp_on_extern_linked_int<&i>();
^
编译器非常有用。它明确指出,由于i
没有外部链接,因此编译失败。
i
的注释定义具有内部链接,因为它是不带外部的限定常量。(§3.4.6)
Variables at namespace scope that are declared const and not extern have internal linkage.
技巧的一部分是不要编译为C++11。
为什么C++03要求模板参数具有外部链接?
例如
#include <iostream>
namespace
{
extern int x = 10;
void f( int y )
{
extern int x;
std::cout << x + y << std::endl;
}
}
int main()
{
int y = 15;
f( y );
return 0;
}
根据C++标准
6块范围中声明的函数的名称和块作用域外部声明声明的变量具有链接。如果具有链接的实体的可见声明具有相同的名称和类型,忽略在最内层外部声明的实体封闭命名空间范围,块范围声明声明同一实体,并接收先前声明的链接。如果存在不止一个这样的匹配实体,程序不正规。否则,如果未找到匹配的实体,则块作用域实体接收外部链接
- .cpp和.h文件中的模板专用化声明
- 未在作用域中声明unordered_map
- C++避免重复声明的语法是什么
- 如何确保C++函数在定义之前声明(如override关键字)
- 错误:未在此范围内声明'reverse'
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 为什么在定义函数之前先声明它
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- #ifdef和未声明的标识符
- 没有显式声明的int[]中的foreach
- 在基于范围的for循环中使用结构化绑定声明
- 在将变量声明为引用时,堆在释放后使用
- C++:无法访问声明的受保护成员
- 为什么我不能在一个类的不同行中声明和定义成员变量?
- 错误:变量或字段'PrintEntity'声明无效无效打印实体(实体 e);
- 为什么名称查找在找到使用 using 指令隐式声明的实体时不停止?
- 合法地转发声明 C 标准库实体,但不C++标准库实体
- 友元声明及其表示的实体
- 在具有外部链接的匿名命名空间中声明的实体的示例
- 声明名称、引入名称和声明实体之间的区别