在具有外部链接的匿名命名空间中声明的实体示例

时间:2014-09-24 20:53:05

标签: c++ c++11 namespaces language-lawyer linkage

鉴于§3.5/ 4和§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]:

  

虽然未命名的命名空间中的实体可能具有外部链接,   他们的翻译专有名称有效   单位,因此永远不会从任何其他翻译单位看到。

3 个答案:

答案 0 :(得分:5)

您正在查看标准中的缺陷。

使得未命名的命名空间成员具有内部链接的更改在2010年11月的C ++ 11标准化过程中发生得相当晚(CWG issue 1113)。因此,标准中的许多地方需要改变,但事实并非如此。其中一个是你引用的脚注。

CWG issue 1603,目前处于“就绪”状态(阅读:该决议很可能会在下一次委员会会议上通过),将解决此问题以及与未命名的命名空间成员进行内部链接相关的许多其他问题

答案 1 :(得分:1)

这是一个很好的问题,因为它很难证明。我们可以利用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的注释定义具有内部链接,因为它是没有extern的限定const。 (§3.4.6)

Variables at namespace scope that are declared const and not extern have internal linkage.

部分技巧不是编译为C ++ 11。

Why did C++03 require template parameters to have external linkage?

答案 2 :(得分:0)

例如

#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在块作用域中声明的函数的名称和a的名称   由块作用域extern声明声明的变量具有链接。如果   有一个实体的可见声明,其中有一个链接   相同的名称和类型,忽略在最里面之外声明的实体   封闭命名空间范围,块范围声明声明   同一实体并接收先前声明的链接。如果   有多个这样的匹配实体,程序是   病态的。否则,如果未找到匹配的实体,则阻止范围   实体接收外部链接