未命名命名空间中嵌套的实体在常规命名空间中是否具有内部链接?

17
在C++中,将函数或变量放在未命名的命名空间中会使其链接变为内部链接,即与在文件级别上声明为static相同,但符合C++的习惯用法。
那么,在普通命名空间内部的未命名命名空间呢?它是否仍然保证内部链接?
// foo.cpp

void func1() {
    // external linkage
}

static void func2() {
    // internal linkage
}

namespace {
    void func3() {
        // internal linkage
    }
}

namespace ns1 {
    void func4() {
        // external linkage
    }
    
    namespace {
        void func3() {
            // still internal linkage?
        }
    }
}

1
错误的假设。匿名命名空间内的变量具有外部链接,除非声明为 static - MSalters
1
@MSalters: 我认为随着 C++11 的到来情况已经改变了。§3.5/4:未命名的命名空间或直接或间接在未命名的命名空间中声明的命名空间具有内部链接。所有其他命名空间都具有外部链接。 - legends2k
1
@legends2k:那是另一个更改的一部分,它使这些名称成为模板参数有效(在C++03中,模板参数需要外部链接,匿名命名空间中定义的常量满足了此要求)。 - MSalters
3个回答

15
C++11(草案N3337)§3.5/4:(强调我)
一个未命名的命名空间或直接或间接在未命名的命名空间中声明的命名空间具有内部链接。所有其他命名空间具有外部链接。如果命名空间作用域的名称未被赋予上述内部链接,则如果它是以下内容之一的名称,则具有与封闭命名空间相同的链接 - 变量; 或者 - 函数; 或者 - 命名类(第9条),或在typedef声明中定义为typedef名称以供链接目的使用的无名类(7.1.3); 或者 - 命名枚举(7.2),或在typedef声明中定义为typedef名称以供链接目的使用的无名枚举(7.1.3); 或者 - 属于具有链接的枚举的枚举器; 或者 - 模板。
这保证了任何未命名的命名空间都具有内部链接。
在命名(正常)命名空间内,匿名命名空间仍然被保证具有内部链接,因此符合C++11标准。
将函数或变量放置在匿名命名空间中使其链接成为内部的,即与在文件级别上声明为static相同,但是这是C++习惯用法。

在C++11中,这种情况下使用static的做法已经被取消了废弃状态;虽然未命名命名空间是static的更好选择 ,但是它有时会失败,这可以通过static解决;在C++11中引入了inline namespace以解决这个问题。


15

匿名命名空间中的实体不一定具有内部链接,它们实际上可能具有外部链接。

由于未命名的命名空间有一个在编译它的翻译单元中唯一的名称,因此无论它们的链接是什么,你都不能从该翻译单元之外引用其中声明的实体。

C++标准规定(C++03 7.3.1.1/note 82):

尽管未命名命名空间中的实体可能具有外部链接,但它们实际上被限定为其翻译单元中唯一的名称,并且因此永远不能从任何其他翻译单元中看到。


2
一个快速的跟进:您是否知道具有内部链接是否会在编译器进行优化时帮助编译器做出更好的代码转换决策,还是这不是问题? - Alex B
@Alex B:这是一个好问题。我猜测,如果编译器或链接器可以对具有内部链接的实体进行优化,它们也可以对未命名命名空间中的实体进行相同的优化。不过我不能确定。这里的其他人肯定比我更清楚。 - James McNellis

5
$3.5/3 - “如果命名空间范围(3.3.6)的名称:

— 是静态声明的变量、函数或函数模板;或

— 明确声明为const且未明确声明为extern或先前声明为具有外部链接的变量;或

— 是匿名联合体的数据成员,则具有内部链接。

所以,我怀疑你程序中的任何一个名称'func3'和'func4'都没有内部链接。它们具有外部链接。然而,正如James的引用所述,它们只是不能从其他翻译单元中引用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接