什么是单一定义规则?

发布于 2024-10-02 06:59:17 字数 90 浏览 1 评论 0原文

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

随心而道 2024-10-09 06:59:17

真相就在标准中(3.2 一个定义规则):

翻译单元不得包含更多内容
比任何变量的一个定义,
函数、类类型、枚举类型
或模板。

[...]

每个程序都应准确包含
每个非内联的一个定义
使用的函数或对象
该程序
;无需诊断。
定义可以明确地出现
在程序中,可以找到
标准或用户定义的库,或
(在适当的时候)它是隐式的
定义(见 12.1、12.4 和 12.8)。一个
内联函数应定义在
它所在的每个翻译单元
使用过。

The truth is in the standard (3.2 One definition rule) :

No translation unit shall contain more
than one definition of any variable,
function, class type, enumeration type
or template.

[...]

Every program shall contain exactly
one definition of every non-inline
function or object that is used in
that program
; no diagnostic required.
The definition can appear explicitly
in the program, it can be found in the
standard or a user-defined library, or
(when appropriate) it is implicitly
defined (see 12.1, 12.4 and 12.8). An
inline function shall be defined in
every translation unit in which it is
used.

扛刀软妹 2024-10-09 06:59:17

“单一定义规则”是 [basic.def.odr] C++ 标准中的子条款。
本节包含许多规则。
我将总结最重要的一些。

首先,您不能在同一个文件中多次定义某个内容。如果您在多个文件中定义某些内容,则定义必须相同。此外,如果你使用某种东西,它的定义就必须存在。

以下部分更详细地描述了这一点。

每个翻译单元只有一个定义[1]

第一个也是最基本的规则是 [basic.def.odr] p2

翻译单元不得包含任何一个以上的定义可定义项

例如,这意味着您不能编写以下内容:

void foo() {} // OK
void foo() {} // error, more than one definition of foo in the same TU

实际上,编译器会引发错误,告诉您“重新定义 foo”。


[1] 翻译单元基本上是一个 C++ 源文件。标头不是翻译单元,它包含在翻译单元中。

每个程序只有一个定义,不包括模板和内联

此外,[basic.def.odr] p14 调节多个翻译单元之间发生的情况:

对于任何在多个翻译单元中定义的可定义项D

  • 如果 D 是非内联非模板化函数或变量,或者
  • 如果不同翻译单元中的定义不满足以下要求,

程序格式不正确; [...]

例如,这意味着您不能在不同的源文件中有两个定义 void foo() {}。实际上,这会导致链接器错误告诉您“foo 的多个定义”。

模板和内联函数很特殊,因为它们可以在多个翻译单元中定义,只要这些定义遵循严格的规则即可。本质上,定义必须是等效的。例如:

// a.cpp
inline int bar() { return 0; }
// b.cpp
inline int bar() { return 0; } // OK
// c.cpp
inline int bar() { return 1; } // ill-formed, no diagnostic required

请注意,此规则对于标头非常重要。 #include 本质上是将代码复制/粘贴到翻译单元中,因此在标头中定义任何内容都有违反此规则的风险。

odr 使用的所有内容都必须定义[2]

第三,它还定义了所谓的 odr-use。直观上, odr-use 意味着您使用了一些以一种其定义需要存在的方式构建。
例如:

int foo(); // declaration, not a definition

using foo_type = decltype(foo); // decltype (unevaluated operand) is not odr-use.
int x = foo(); // calling a function is odr-use

odr-use 会产生后果,在 [basic.def.odr] p11 中说明:

每个程序应至少包含每个函数或变量的一个定义 丢弃之外的该程序中使用了“noreferrer”odr声明;无需诊断。

实际上,如果您使用一个函数并且它没有在任何地方定义,您会收到一个链接器错误,告诉您“没有定义 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:

No translation unit shall contain more than one definition of any definable item.

For example, this means you cannot write the following:

void foo() {} // OK
void foo() {} // error, more than one definition of foo in the same TU

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 any definable item D with definitions in multiple translation units,

  • if D is a non-inline non-templated function or variable, or
  • if the definitions in different translation units do not satisfy the following requirements,

the program is ill-formed; [...]

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:

// a.cpp
inline int bar() { return 0; }
// b.cpp
inline int bar() { return 0; } // OK
// c.cpp
inline int bar() { return 1; } // ill-formed, no diagnostic required

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:

int foo(); // declaration, not a definition

using foo_type = decltype(foo); // decltype (unevaluated operand) is not odr-use.
int x = foo(); // calling a function is odr-use

To odr-use something has consequences, stated in [basic.def.odr] p11:

Every program shall contain at least one definition of every function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文