简体   繁体   English

C++ 中如何使用内联说明符来保留一个定义规则?

[英]How is the inline specifier used in C++ to preserve the one definition rule?

I've been trying to figure out how the inline specifier preserves ODR.我一直在试图弄清楚inline说明符如何保留 ODR。 So far, with everything I've written it seems unnecessary because include guards ensure that definitions are only included once.到目前为止,我写的所有内容似乎都没有必要,因为包含保护确保定义只包含一次。

Suppose I have the following definition in a file called constants.h假设我在名为constants.h的文件中有以下定义

#ifndef CONSTANTS_H
#define CONSTANTS_H

namespace constants {
    inline const double pi { 3.14159255358979323846 };
    inline const double e  { 2.71828182845904523536 };
}

#endif

From my understanding of inline in relation to the ODR, the inline specifier is written to ensure that the definition of these constants are only initialized once across multiple translation units.根据我对与 ODR 相关的inline理解,编写inline说明符是为了确保这些常量的定义仅在多个翻译单元中初始化一次。 So if I include this file in a.cpp and b.cpp everything should be good.因此,如果我将这个文件包含在a.cppb.cpp一切都应该很好。

Now, let's remove the inline keyword.现在,让我们删除inline关键字。

#ifndef CONSTANTS_H
#define CONSTANTS_H

namespace constants {
    const double pi { 3.14159255358979323846 };
    const double e  { 2.71828182845904523536 };
}

#endif

Now if I include this in a.cpp and b.cpp no issues.现在,如果我将其包含在a.cppb.cpp没有问题。 I guess this is because of the include guards which ensure multiple definitions of the same thing don't occur twice.我想这是因为包含警卫确保同一事物的多个定义不会出现两次。

Next, let's remove the include guards接下来,让我们移除包含守卫

namespace constants {
    const double pi { 3.14159255358979323846 };
    const double e  { 2.71828182845904523536 };
}

Still no problem.还是没有问题。 Maybe because const qualified variable definitions have internal linkage by default.可能是因为const限定的变量定义默认具有内部链接。 As a result, including constants.h in a.cpp and b.cpp makes each of these definitions internal by default to their respective translation units.因此,在a.cppb.cpp包含constants.h使这些定义中的每一个都默认为各自的翻译单元内部。

Having a hard time breaking ODR across multiple translation units.很难打破跨多个翻译单元的 ODR。 Let's remove const now.现在让我们删除 const。

namespace constants {
    double pi { 3.14159255358979323846 };
    double e  { 2.71828182845904523536 };
}

NOW!现在! ODR is broken across multiple translation units. ODR 跨越多个翻译单元。 Let's try fixing this with inline so that the compiler knows to only define these variables once.让我们尝试使用inline修复此问题,以便编译器知道只定义这些变量一次。

namespace constants {
    inline double pi { 3.14159255358979323846 };
    inline double e  { 2.71828182845904523536 };
}

Ok, no more errors, this file can once again be included in multiple translation units.好的,没有更多错误,这个文件可以再次包含在多个翻译单元中。 So why is considered "best practice" to declare constants in header files as inline ?那么为什么将头文件中的常量声明为inline被认为是“最佳实践”? It seems to take a lot of effort to break ODR and inline is redundant in the presence of include guards.打破 ODR 似乎需要付出很多努力,并且在包含守卫的情况下inline是多余的。

Constants that are not declared with the specifier extern have internal linkage.未使用说明符 extern 声明的常量具有内部链接。

So all compilation units that include these declarations所以所有包含这些声明的编译单元

namespace constants {
    const double pi { 3.14159255358979323846 };
    const double e  { 2.71828182845904523536 };
}

have their own constants pi and e.有自己的常数 pi 和 e。

From the C++ 14 Standard (3.5 Program and linkage)来自 C++ 14 标准(3.5 程序和链接)

3 A name having namespace scope (3.3.6) has internal linkage if it is the name of 3 具有命名空间范围 (3.3.6) 的名称具有内部链接,如果它是

(3.2) — a variable of non-volatile const-qualified type that is neither explicitly declared extern nor previously declared to have external linkage; (3.2) — 非 volatile const 限定类型的变量,既未显式声明为 extern 也未先前声明为具有外部链接; or或者

Opposite to the above declarations these declarations与上述声明相反,这些声明

namespace constants {
    double pi { 3.14159255358979323846 };
    double e  { 2.71828182845904523536 };
}

have external linkage.有外部联动。 So the compiler issues an error if these declarations (that are also definitions) are included in more than one compilation unit because the one definition rule is broken.因此,如果这些声明(也是定义)包含在多个编译单元中,则编译器会发出错误消息,因为一个定义规则被破坏。

You could make the above variables to have the internal linkage if you declare them in an unnamed namespace as for example例如,如果您在未命名的命名空间中声明它们,则可以使上述变量具有内部链接

namespace constants {
    namespace {
        double pi { 3.14159255358979323846 };
        double e  { 2.71828182845904523536 };
    }
}

As for these declarations至于这些声明

namespace constants {
    inline double pi { 3.14159255358979323846 };
    inline double e  { 2.71828182845904523536 };
}

then inline variables with external linkage may be defined in more than one compilation unit.然后可以在多个编译单元中定义具有外部链接的内联变量。 Moreover an inline variable shall be defined in each compilation unit where it is ODR-used.此外,应在每个使用 ODR 的编译单元中定义内联变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM