c++11:为啥静态 constexpr 的类内初始化不是定义?
Posted
技术标签:
【中文标题】c++11:为啥静态 constexpr 的类内初始化不是定义?【英文标题】:c++11: Why a in-class initialization of a static constexpr not a definition?c++11:为什么静态 constexpr 的类内初始化不是定义? 【发布时间】:2021-09-14 01:56:16 【问题描述】:考虑以下简单:
#ifndef TEST_H
#define TEST_H
class Test
public:
static constexpr int a = 1;
#endif
注意:
-
没有因宏而违反 ODR。
为什么 constexpr static int a 不被视为定义,因为它是在类 Test 中定义的?因为它不是一个定义,因此它需要类之外的以下内容。为什么?
constexpr int Test::a;
【问题讨论】:
自 C++17 起不再需要此项。 在内联变量之前,所有静态成员变量都必须在单个 TU 中定义,以避免破坏 ODR。 C++17 引入了内联变量,让这个问题迎刃而解。 详细解释见softwareengineering.stackexchange.com/questions/145299。 “由于宏没有 ODR 违规。” - 包含守卫不能防止 ODR 违规。它们保护单个 TU 不被重新纳入,但 ODR 适用于整个计划及其所有 TU! 请看下面我对杰瑞的问题。发送 【参考方案1】:为什么静态 constexpr 的类内初始化不是定义?
因为一个定义规则 (ODR)。该规则规定,每个非内联非成员变量和静态成员变量都必须有一个定义。由于其性质,类定义通常包含在多个翻译单元中。如果类定义包含变量定义,则包含在多个翻译单元中将违反 ODR。
从 C++17 开始,该语言具有内联变量,因此您可以在类定义中定义此类内联变量。
【讨论】:
我了解 ODR,但这是我的问题。如果我们如上所述在该文件本身中有宏#define,为什么上述 constexpr 静态数据成员会违反 ODR?认为多个文件可能包含这个类.. 总会有 1 个 Test 类定义。 @yapkm01 如果您编译g++ -c a.cpp; g++ -c b.cpp; g++ a.o b.o
并且 a.cpp 和 b.cpp 都包含您的标头,则包含保护不会阻止类定义出现在可执行文件中两次,因为每个 cpp 文件都是单独编译的所以每个人都必须包含这个类..
如果 a.cpp 和 b.cpp 都包含具有类 Test 的标头,并且正如您所说的标头保护适用于每个 TU,那么如何链接它们将满足 ODR,因为 a.o 和 b.o 都包含类 Test ?
@yapkm01 因为 ODR 允许在每个 TU 中定义类,前提是定义相同。
如果将相同的类视为定义,为什么跨 TU 允许相同的类。就像 int a = 1;定义不能跨 TU 重复?除非你说在这个阶段不涉及存储(?)类中的 constexpr 静态成员呢?他们不被认为是定义吗?看起来不像,因为编译器只是使用它们来替换需要的地方(?)以上是关于c++11:为啥静态 constexpr 的类内初始化不是定义?的主要内容,如果未能解决你的问题,请参考以下文章