我一直试图弄清楚 inline
说明符保留 ODR。到目前为止,我写的所有东西似乎都没有必要,因为包含保护确保定义只包含一次。
假设我在名为 constants.h
的文件中有以下定义
#ifndef CONSTANTS_H
#define CONSTANTS_H
namespace constants {
inline const double pi { 3.14159255358979323846 };
inline const double e { 2.71828182845904523536 };
}
#endif
以我对inline
的理解关于 ODR,inline
编写说明符以确保这些常量的定义仅在多个翻译单元中初始化一次。因此,如果我将此文件包含在 a.cpp
中和 b.cpp
一切都应该很好。现在,让我们删除
inline
关键词。#ifndef CONSTANTS_H
#define CONSTANTS_H
namespace constants {
const double pi { 3.14159255358979323846 };
const double e { 2.71828182845904523536 };
}
#endif
现在,如果我将其包含在 a.cpp
中和 b.cpp
没有问题。我想这是因为包含 guard 确保同一事物的多个定义不会出现两次。接下来,让我们移除包含守卫
namespace constants {
const double pi { 3.14159255358979323846 };
const double e { 2.71828182845904523536 };
}
还是没问题。也许是因为const
默认情况下,限定的变量定义具有内部链接。结果,包括constants.h
在 a.cpp
和 b.cpp
默认情况下,将这些定义中的每一个都设置为它们各自的翻译单元的内部。很难打破跨多个翻译单元的 ODR。现在让我们删除 const。
namespace constants {
double pi { 3.14159255358979323846 };
double e { 2.71828182845904523536 };
}
现在! ODR 跨越多个翻译单元。让我们尝试用 inline
解决这个问题这样编译器就知道只定义这些变量一次。namespace constants {
inline double pi { 3.14159255358979323846 };
inline double e { 2.71828182845904523536 };
}
好的,没有更多错误,这个文件可以再次包含在多个翻译单元中。那么为什么将头文件中的常量声明为 inline
被认为是“最佳实践”? ?打破ODR和inline
好像要下很多功夫在包含守卫存在的情况下是多余的。
最佳答案
未使用说明符 extern 声明的常量具有内部链接。
所以所有包含这些声明的编译单元
namespace constants {
const double pi { 3.14159255358979323846 };
const double e { 2.71828182845904523536 };
}
有自己的常数 pi 和 e。来自 C++ 14 标准(3.5 程序和链接)
3 A name having namespace scope (3.3.6) has internal linkage if it is the name of
(3.2) — a variable of non-volatile const-qualified type that is neither explicitly declared extern nor previously declared to have external linkage; or
与上述声明相反,这些声明
namespace constants {
double pi { 3.14159255358979323846 };
double e { 2.71828182845904523536 };
}
有外部联动。因此,如果这些声明(也是定义)包含在多个编译单元中,则编译器会发出错误消息,因为一个定义规则被破坏。例如,如果您在未命名的命名空间中声明它们,则可以使上述变量具有内部链接
namespace constants {
namespace {
double pi { 3.14159255358979323846 };
double e { 2.71828182845904523536 };
}
}
至于这些声明namespace constants {
inline double pi { 3.14159255358979323846 };
inline double e { 2.71828182845904523536 };
}
然后可以在多个编译单元中定义具有外部链接的内联变量。此外,应在 ODR 使用的每个编译单元中定义一个内联变量。
关于c++ - C++ 中如何使用内联说明符来保留一个定义规则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69966903/