【问题标题】: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

注意:

  1. 没有因宏而违反 ODR。
  2. 为什么 constexpr static int a 不被视为定义,因为它是在类 Test 中定义的?因为它不是一个定义,因此它需要类之外的以下内容。为什么?

constexpr int Test::a;

【问题讨论】:

  • 自 C++17 起不再需要此项。
  • 在内联变量之前,所有静态成员变量都必须在单个 TU 中定义,以避免破坏 ODR。 C++17 引入了内联变量,让这个问题迎刃而解。
  • “由于宏没有 ODR 违规。” - 包含守卫不能防止 ODR 违规。它们保护单个 TU 不被重新纳入,但 ODR 适用于整个计划及其所有 TU!
  • 请看下面我对杰瑞的问题。发送

标签: c++ c++11


【解决方案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 静态成员呢?他们不被认为是定义吗?看起来不像,因为编译器只是使用它们来替换需要的地方(?)
猜你喜欢
  • 2013-10-19
  • 2016-05-10
  • 1970-01-01
  • 2013-01-10
  • 1970-01-01
  • 2014-10-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多