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

C++ 在具有外部链接的匿名命名空间中声明的实体示例,c++,c++11,namespaces,language-lawyer,linkage,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)

鉴于§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]:

尽管未命名命名空间中的实体可能具有外部链接, 它们实际上是由其翻译的唯一名称限定的 因此,从任何其他翻译单位都看不到

比如说

#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;
}
#包括
名称空间
{
外部INTX=10;
空f(整数y)
{
外部INTX;

STD::CUT< P>这是一个很好的问题,因为它很难演示。我们可以利用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>();
}
取消注释
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>();
                              ^
$g++-4.8 main.cpp-o main
main.cpp:在函数“int main()”中:
main.cpp:17:30:错误:“&{anonymous}::i”不是的有效模板参数
键入“int*”,因为“{anonymous}::i”没有外部链接
外部链接上的温度();
^
编译器非常有用。它明确指出,因为
i
没有外部链接,所以编译失败

i
的注释定义具有内部链接,因为它是无外部的限定常量。(§3.4.6)

命名空间范围中声明为const而非extern的变量具有内部链接。

技巧的一部分是不作为C++11编译


您看到的是标准中的缺陷

使未命名命名空间成员具有内部链接的更改发生在2010年11月的C++11标准化过程中相当晚的时候()。因此,标准中的许多地方需要更改,但没有更改。您引用的脚注就是其中之一


,目前处于“准备就绪”状态(内容为:该决议可能在委员会下次会议上通过),将修复此问题以及与向未命名命名空间成员提供内部链接相关的许多其他问题。

我认为§3.5/2第一个要点中的
不是排他性的。因此,我不同意在您的示例中
x
具有外部链接。@唤醒用quakifier extern.S声明的巴西x Os automatica变量o如果在包含链接的封闭名称空间中有前面的x声明,那么x具有相同的链接。请参见3.5/6.§3.5/6只是告诉您,本地
x
具有与在名称空间范围
extern int x=10;
中声明的
x
相同的链接。但这并不意味着该
x
具有外部链接。请参见§3.5/4第一点:
一个名称的命名空间作用域没有在上面给出内部链接,如果它是一个变量的名称,则它与封闭的命名空间具有相同的链接;
。另请参见§7.1.1/6,其中引用了§3.5,关于使用
外部
说明符声明的名称的链接。@Wake Wake Brazis您不理解您读到的内容。变量x被定义为在未命名的命名空间中具有外部链接。函数中定义的局部变量也具有外部链接,因为在封闭的命名空间中有一个具有相同名称和链接的变量。有什么问题吗?!我怀疑脚注可能是C++03的遗留部分,其中未命名名称空间中的名称具有外部链接(因为否则它们不能用作模板参数)。作者只是忘了删除它。A好吧,你已经证明了未命名的命名空间在C++03中有外部链接,因此你甚至不需要声明
extern int i;
,因为编译器将声明
int i=5;
识别为具有外部链接。对于C++11,我只能引用标准,但既然您已经在OP中提供了相关的引用,那么就不清楚您在寻找什么。知道名称空间和其中的变量不一定具有相同的链接有帮助吗?另外,在C++11中,打破示例的是模板参数,而不是链接规则。在C++11中,代码编译是因为声明
extern int i;
不会在声明中添加任何内容,即变量
i
继续具有内部链接,尽管有
extern
说明符。这正是我要找的。答案很好(+1)。
$ 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>();
                              ^