ODR 和内部链接

rai*_*ner 5 c++ one-definition-rule linkage c++11

假设我在一个程序中有两个编译单元,每个编译单元都声明一个具有相同签名的非内联函数,但实现不同,例如

// a.cpp
namespace internal {
    int foo(int a) {
        return a+1;
    }
}

int main() {
}
Run Code Online (Sandbox Code Playgroud)

// b.cpp
namespace internal {
    int foo(int b) {
        return b+2;
    }
}
Run Code Online (Sandbox Code Playgroud)

编译/链接这个(g++ 4.8.3 with -std=c++11),我收到错误

b.cpp:(.text+0x0): multiple definition of `internal::foo(int)'
Run Code Online (Sandbox Code Playgroud)

这是相当预期的,因为据我了解,这只是违反了单一定义规则

odr 使用的每个非内联函数或变量(见下文)的唯一一个定义需要出现在整个程序(包括任何标准库和用户定义库)中。

现在,将 更改namespace internal为未命名的名称空间,错误就会消失。直观上,这对我来说是有意义的,因为我正在将函数从外部链接更改为内部链接

在命名空间范围内声明的以下任何名称都具有外部链接,除非该命名空间未命名或包含在未命名命名空间内 (C++11 起):上面未列出的变量和函数(即未声明为 static [... ]) ...

[A]所有在未命名命名空间或未命名命名空间内的命名空间中声明的名称,即使是显式声明为 extern 的名称,也具有内部链接。

但是,我无法在一个定义规则中找到任何可以免除具有内部链接的函数的内容。因此,我的问题是:我的直觉推理是否正确,或者我仍然违反具有内部链接的函数的单一定义规则(并且编译器/链接器不再报告它)?此外,标准(或 cppreference.com :))在哪里说明它是否可以?

bol*_*lov 4

n4713

\n\n
\n

\xc2\xa76.5 程序和链接 [basic.link]

\n\n

当一个名称可能表示同一个对象、引用、函数、类型、模板、命名空间或值作为由另一个作用域中的声明引入的名称时,则称该名称具有链接:

\n\n

(2.1) \xe2\x80\x94 当名称具有外部链接时,它所表示的实体可以被其他翻译单元的范围或同一翻译单元的其他范围的名称引用。

\n\n

(2.2) \xe2\x80\x94 当名称具有内部链接时,它所表示的实体可以被同一翻译单元中其他范围的名称引用。

\n\n

\xe2\x80\x94 当名称没有链接时,它所表示的实体不能被其他范围的名称引用。

\n
\n\n

这基本上是说(在未命名命名空间的情况下)foo来自的名称和每个来自的a.cpp名称引用不同的实体。因此,同一个对象没有两个定义,因此不会违反 ODR。foob.cpp

\n