什么是单一定义规则?
C++ 中的单一定义规则到底说了什么? 我能找到的唯一值得信赖的地方是《C++ 编程语言,第 3 版》。编辑,第 9.2.3 页。除此之外,该规则还有其他官方定义吗?
What exactly does the One-Definition Rule in C++ say?
The only trustworthy occurrence I can find is in The C++ Programming Language, 3rd. ed., P. 9.2.3. Is there any official definition of the rule except that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
真相就在标准中(3.2 一个定义规则):
The truth is in the standard (3.2 One definition rule) :
“单一定义规则”是 [basic.def.odr] C++ 标准中的子条款。
本节包含许多规则。
我将总结最重要的一些。
首先,您不能在同一个文件中多次定义某个内容。如果您在多个文件中定义某些内容,则定义必须相同。此外,如果你使用某种东西,它的定义就必须存在。
以下部分更详细地描述了这一点。
每个翻译单元只有一个定义[1]
第一个也是最基本的规则是 [basic.def.odr] p2:
例如,这意味着您不能编写以下内容:
实际上,编译器会引发错误,告诉您“重新定义 foo”。
[1] 翻译单元基本上是一个 C++ 源文件。标头不是翻译单元,它包含在翻译单元中。
每个程序只有一个定义,不包括模板和
内联
此外,[basic.def.odr] p14 调节多个翻译单元之间发生的情况:
例如,这意味着您不能在不同的源文件中有两个定义
void foo() {}
。实际上,这会导致链接器错误告诉您“foo 的多个定义”。模板和内联函数很特殊,因为它们可以在多个翻译单元中定义,只要这些定义遵循严格的规则即可。本质上,定义必须是等效的。例如:
请注意,此规则对于标头非常重要。 #include 本质上是将代码复制/粘贴到翻译单元中,因此在标头中定义任何内容都有违反此规则的风险。
odr 使用的所有内容都必须定义[2]
第三,它还定义了所谓的 odr-use。直观上, odr-use 意味着您使用了一些以一种其定义需要存在的方式构建。
例如:
odr-use 会产生后果,在 [basic.def.odr] p11 中说明:
实际上,如果您使用一个函数并且它没有在任何地方定义,您会收到一个链接器错误,告诉您“没有定义 foo”。
[2] 这个术语最初只是被称为“使用”; C++11 引入了术语“odr-use”以使其更加正式。
The "One-Definition Rule" is the [basic.def.odr] subclause in the C++ standard.
This subclause contains a number of rules.
I will sumarize the most important ones.
Firstly, you cannot define something multiple times in the same file. If you define something in multiple files, the definitions have to be identical. Furthermore, if you use something, a definition of it has to exist.
The sections below describe this in more detail.
Only one definition per translation unit[1]
The first and most basic rule is [basic.def.odr] p2:
For example, this means you cannot write the following:
In practice, the compiler would raise an error telling you "re-definition of foo".
[1] A translation unit is basically one C++ source file. A header is not a translation unit, it is included into translation units.
Only one definition per program, excluding templates and
inline
Furthermore, [basic.def.odr] p14 regulates what happens across multiple translation units:
For example, this means that you cannot have two definitions
void foo() {}
in different source files. In practice, this would result in a linker error telling you "multiple defintions of foo".Templates and inline functions are special, because they can be defined in multiple translation units as long as those definitions follow strict rules. Essentially, the definitions have to be equivalent. For example:
Note that this rule is very important for headers.
#include
essentially copies/pastes code into translation units, so defining anything in a header risks violating this rule.Everything that is odr-used[2] must be defined
Thirdly, it also defines so-called odr-use. Intuitively, odr-use means that you use some construct in a way that its definition needs to exist.
For example:
To odr-use something has consequences, stated in [basic.def.odr] p11:
In practice, if you use a function and it isn't defined anywhere, you get a linker error telling you "no definition of foo".
[2] This term was originally just called "use"; C++11 introduced the term "odr-use" to make it more formal.