ODR和内部链接

时间:2019-03-20 16:44:18

标签: c++ c++11 linkage one-definition-rule

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

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

int main() {
}

// b.cpp
namespace internal {
    int foo(int b) {
        return b+2;
    }
}

对此进行编译/链接(带有-std=c++11的g ++ 4.8.3),出现错误

b.cpp:(.text+0x0): multiple definition of `internal::foo(int)'

这是可以预期的,因为据我了解,这完全违反了one definition rule

  

每个非内联函数或变量只有一个定义   必须使用奇数个(见下文)   程序(包括任何标准库和用户定义库)。

现在,将namespace internal更改为未命名的名称空间,该错误消失了。直观上,这对我来说很有意义,因为我正在从external to internal linkage更改函数:

  

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

  

[A]在未命名的名称空间或名称空间中声明的名称   在一个未命名的命名空间中,即使是明确声明为extern的命名空间,   有内部联系。

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

1 个答案:

答案 0 :(得分:2)

n4713

  

§6.5程序和链接[basic.link]

     

当一个名称可能表示同一对象时,它被称为具有链接,   引用,函数,类型,模板,名称空间或值作为名称   由声明引入另一个范围:

     

(2.1)-名称具有外部链接时,其表示的实体可以是   由其他翻译单位范围或   同一翻译单元的其他范围。

     

(2.2)-名称具有内部链接时,它表示的实体可以   在同一译文中被其他范围的名称所指   单位。

     

-当一个名称没有链接时,它所表示的实体不能被引用   以其他作用域的名称命名。

这基本上表示(对于未命名的名称空间)foo中的名称a.cppfoo中的名称b.cpp分别指不同的实体。因此,您没有同一个对象的两个定义,因此不会违反ODR。