当前位置: 首页 > 知识库问答 >
问题:

Constexr数组成员是否编译时间常量?

马浩淼
2023-03-14

是代码片段

struct Parameters {
   static constexpr int n = 2;
   static constexpr double v[n] = {4.0, 5.0};
};

如果是,参数::v[0]参数::v[1]是编译时常量,还是指针参数::v本身就是constexr(无论编译时意味着什么)?

如您所见,我通常对 constexpr 数组及其在类/结构中的初始化感到有些困惑。请随意回答我的具体问题,还可以提及有关此主题的常见陷阱等。

共有3个答案

汤玉宸
2023-03-14
struct Parameters {
   static constexpr int n = 2;
   static constexpr double v[n] = {4.0, 5.0};
};

据我所知,这个片段本身当然是合法的。C 11标准第7.1.5节[dcl.constexpr]规定

constexr说明符只能应用于…文字类型的静态数据成员的声明

文本类型在 3.9 中定义:

类型是文字类型,如果它是:

-标量类型;或

—文字类型的数组

因此,据我所知,<code>static constexpr double v[2]={…}</code>当然是有效的。

至于数组的成员是否是< code>constexpr...我不确定。如果我们宣布

constexpr double d = Parameter::v[1];

然后 g 和 clang 都可以编译它,但 clang 版本无法与对 Parameters::v 的未定义引用链接。 我不知道这是否指向 Clang 错误,或者构造是否无效。

穆劲
2023-03-14
struct Parameters {
  static constexpr int n = 2;
  static constexpr double v[n] = {4.0, 5.0};
};

int main() {
  constexpr int a = Parameters::v[0];
  return 0;
}

gcc 4.8.2上的这段代码编译成以下代码:

0000000000000000 <main>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   c7 45 fc 04 00 00 00    mov    DWORD PTR [rbp-0x4],0x4
   b:   b8 00 00 00 00          mov    eax,0x0
  10:   5d                      pop    rbp
  11:   c3                      ret 

所以是的,它是一个编译时常数。

clang 3.4产生类似的代码:

0000000000000000 <main>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   b8 00 00 00 00          mov    eax,0x0
   9:   c7 45 fc 00 00 00 00    mov    DWORD PTR [rbp-0x4],0x0
  10:   c7 45 f8 04 00 00 00    mov    DWORD PTR [rbp-0x8],0x4
  17:   5d                      pop    rbp
  18:   c3                      ret

同样,它是一个编译时间常数。

一切都是用 -O0 编译的。

注:如果a被声明为const,那么对于gcc,除了clang-dos之外,没有任何变化,值4不会被直接修改,就像是编译时常量一样。

如果a声明为既不是const也不是const,则两个编译器都无法将参数::v[0]视为编译时常量。

司知
2023-03-14

我认为这个构造没有问题。引用C 11,[dcl.constexpr]

§1 constexpr 说明符应仅适用于变量的定义、函数或函数模板的声明或文字类型的静态数据成员的声明 (3.9)。...

9对象声明中使用的< code>constexpr说明符将对象声明为< code>const。这样的对象应该具有文字类型,并且应该被初始化。如果它是由一个构造函数调用初始化的,那么这个调用应该是一个常量表达式(5.19)。否则,或者如果在引用声明中使用了constexpr说明符,则出现在其初始值设定项中的每个全表达式都应该是常量表达式。用于转换初始化表达式的每个隐式转换和用于初始化的每个构造函数调用应该是常量表达式(5.19)中允许的。

<code>double</code>是一种文字类型,文字类型数组也是如此。这意味着代码中的v[0]v[1]实际上是常量表达式。

 类似资料:
  • 问题内容: 假设我有一个这样的课程: 我的应用程序中的许多其他类都在使用这些选项。现在,我只想更改其中一个选项,而仅部署已编译的类。但是,如果将这些字段插入到消费者类中,这将变得不可能,对吗? 是否有任何选项可以禁用内联编译时间常数? 问题答案: 您可以使用String.intern()获得所需的效果,但应注释您的代码,因为对此知之甚少。即 这样可以防止内联编译时间。由于它是指编译器将放入烫发中的

  • 为什么这个 成员函数,由 评论,当打电话时不被视为 ? 明吉瓦 g 5.1 报告 Visual C 2015 报告 我的文本编辑器坚持调用中的名称与函数定义中的名称相同。 这似乎与不完整的类有关,因为通过定义< code>OUT_OF_CLASS,它可以很好地编译。 但是,为什么< code>n_items_数据有效,为什么这样的规则(对我来说没有意义)?

  • 我试图创建一个编译时常量,这样R8就可以在最终的生产apk中省略调试代码。我遇到了一个路障,不可分配给。 进一步检查后,我发现用wrapper。 这里的问题是: 为什么不能将静态最终布尔值指定给常量值

  • 问题内容: 因此,如果我有一个,由于某种原因,如果我在另一段代码(如)中引用它,则在编译过程中它不会内联到代码中。因此,它不是在被编译之后而是。 问题答案: 您不是编译时间常数,因为JLS 表示 不是。只能在常量表达式中使用的类型是基本类型和。 它的意义是,一个实例(通常)具有语义上重要的对象标识,该标识将其与其他实例区分开。此对象标识不能编码在类文件中……至少,不能用当前的类文件格式编码。(如果

  • 问题内容: 最终变量和编译时间常数之间有什么区别? 考虑以下代码 这是什么意思?何时以及如何为最终变量分配值?在运行时会发生什么,在编译时会发生什么?为什么要给switch一个编译时间常数?Java还有哪些其他结构需要编译时间常数? 问题答案: 问题在于, 所有语句在编译时 都 必须是最终的 。您的第一个陈述 是最终决定 。对于100%,除以外没有其他值。 然而,这 不能保证 对。如果周围有一个i

  • 问题内容: 在关于反射的本教程中,它指出: […]因为泛型是通过类型擦除实现的,因此在编译过程中会删除有关泛型类型的所有信息 我的知识是使用泛型,以便在编译时编译器可以检查类型安全性。即失败快速方法。但是该链接提到类型擦除会在编译期间删除通用信息。 问题答案: 您引用的语句是正确的:编译器在编译过程中在内部使用通用类型信息,在处理源时会生成与类型相关的错误。然后,一旦完成验证,编译器将生成类型擦除