问题标签 [consteval]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
11969 浏览

c++ - 什么是 consteval?

显然,consteval将成为 C++20 中的关键字。它的cppreference 页面当前是空白的。它将是什么以及它与它有什么关系constexpr

0 投票
1 回答
1583 浏览

c++ - consteval 是否允许在函数参数上使用 static_assert?

目前,您不能使用static_assert来验证函数的参数constexpr,即使对它的所有调用确实都是constexpr. 这是有道理的,因为编译器仍然必须创建此函数的非常量实例化,以防其他模块尝试调用它。可悲的是,即使该函数位于static或位于匿名命名空间中也是如此。

然而,C++20 将引入一个新的关键字consteval,类似于constexpr但它不允许以非 constexpr 方式调用函数。在这种情况下,编译器可以确定函数参数在编译时总是已知的。因此,理论上应该可以用static_assert.

问题是:标准允许吗?


例子:

我问是因为我要编写一些用户定义的文字(比示例更复杂)。我可以选择使用编译器扩展来处理验证,或者等待编译器更新并编写完全符合标准的代码。

0 投票
3 回答
230 浏览

c++ - 来自不同翻译单元的 consteval 函数会干扰吗?

我试图深入研究函数存在的含义inline并偶然发现了这个问题。考虑这个小程序(演示):

在没有优化的情况下编译时,程序会产生以下输出:

这可能不是我们想要的,但至少我可以解释它。

  1. 编译器不需要constexpr在编译时计算函数的结果,因此它决定将其推迟到运行时。
  2. constexpr关于函数意味着inline
  3. 我们的get()函数碰巧有不同的实现
  4. 我们没有声明get()函数是静态的
  5. get()链接器必须只选择函数的一种实现

碰巧链接器选择了get()from main.cpp,它返回了 3。

现在到我不明白的部分。我只是get()功能从更改constexprconsteval。现在编译器需要在编译期间计算值,即在链接时间之前(对吗?)。我希望get()函数根本不存在于目标文件中。

但是当我运行它(演示)时,我有完全相同的输出!这怎么可能?.. 我的意思是,我知道这是未定义的行为,但这不是重点。为什么应该在编译时计算的值会干扰其他翻译单元?

UPD:我知道这个功能在 clang 中被列为未实现,但这个问题仍然适用。是否允许符合标准的编译器表现出这种行为?

0 投票
1 回答
455 浏览

c++ - 为什么 consteval 函数允许未定义的行为?

C++ 中的常量表达式有一个非常简洁的属性:它们的求值不能有未定义的行为(7.7.4.7):

表达式 e 是一个核心常量表达式,除非按照抽象机 ([intro.execution]) 的规则对 e 的求值将求值以下之一:

  • ...

  • 具有未定义行为的操作,如本文档的 [intro] 到 [cpp] [注:包括,例如,有符号整数溢出 ([expr.prop])、某些指针算术 ([expr.add])、除以零,或某些移位操作——尾注];

尝试将值存储13!在 aconstexpr int确实会产生一个很好的编译错误

输出:

(顺便说一句,为什么错误说“调用'f(3)'”,而它是对f(13)的调用?..)

然后,我从 中删除constexprx但制作f一个consteval. 根据文档

consteval - 指定一个函数是一个立即函数,也就是说,对函数的每次调用都必须产生一个编译时常量

我确实希望这样的程序会再次导致编译错误。但相反,该程序使用 UB 编译和运行

这是为什么?

UPD:评论者建议这是一个编译器错误。我举报了:https ://bugs.llvm.org/show_bug.cgi?id=43714

0 投票
2 回答
1254 浏览

c++ - 编译器是否允许在运行时调用立即(consteval)函数?

这可能是一个愚蠢的问题,但我很困惑。我有一种感觉,即在编译期间必须执行一个立即 ( )consteval函数,而我们根本无法在二进制文件中看到它的主体。

这篇文章显然支持了我的感觉:

这意味着 [immediate] 函数仅在编译时可见。该函数不会发出符号,您无法获取此类函数的地址,并且调试器等工具将无法显示它们。在这个问题上,立即函数类似于宏。

在Herb Sutter 的出版物中可以找到类似的强烈主张:

请注意,C++20 草案已经包含了第一轮反射相关工作的一部分,这些工作将被纳入标准:保证在编译时运行的consteval 函数,它来自反射工作,专门设计用于操纵反射信息。

然而,有许多证据对这一事实并不十分清楚。

cppreference

consteval - 指定一个函数是一个立即函数,也就是说,对函数的每次调用都必须产生一个编译时常量。

这并不意味着它只能在编译时调用。

来自P1073R3 提案

现在普遍认为,未来语言对反射的支持应该使用 constexpr 函数,但由于“反射函数”通常必须在编译时进行评估,它们实际上很可能是即时函数。

似乎这意味着我的想法,但仍然没有说清楚。来自同一个提案:

然而,有时我们想表达一个函数在调用时(直接或间接)应该总是产生一个常量,而一个非常量的结果应该产生一个错误。

同样,这并不意味着函数必须仅在编译时进行评估。

这个答案

您的代码必须生成编译时常量表达式。但是编译时常量表达式在您使用它的上下文中不是可观察的属性,并且在链接甚至运行时执行它没有副作用!好像没有什么可以阻止

最后,有一个现场演示,其中consteval函数在运行时被清楚地调用。但是,我希望这是因为consteval在 clang 中还没有得到适当的支持,并且行为实际上是不正确的,就像在为什么 consteval 函数允许未定义的行为?

更准确地说,我想听听引用文章的以下哪些陈述是正确的:

  1. 立即函数仅在编译时可见(不能在运行时评估)
  2. 不为立即函数发出符号
  3. 调试器等工具将无法显示即时功能
0 投票
0 回答
59 浏览

c++ - 评估模板括号内的 constexpr

为什么以下将constexpr积分注入模板不起作用

为什么不允许将明确constexpr value注入模板参数的限制?non-type我不明白为什么会有这样的限制?consteval那是不是因为尚未在其中实现clang-10并衰减到...而无法编译constexpr

因为这有效:

0 投票
0 回答
240 浏览

c++ - 将计算从运行时转移到编译时如何使我的代码变慢?

我正在编写一个函数来使用 Stockham FFT 算法计算快速傅里叶变换,并发现如果 FFT 的长度是 2 的幂,则可以在编译时预先计算所有用于计算的“旋转因子”。

在 FFT 计算中,旋转因子计算通常占用总时间的很大一部分,因此理论上这样做应该会大大提高算法的性能。

昨天我花了一整天时间在一个新的编译器 (gcc 10) 上重新实现我的算法,这样我就可以使用 C++20consteval功能在编译时预先计算所有的旋转因子。我成功地做到了,但最终在编译时预先计算所有旋转因子的代码实际上运行得更慢!

这是在运行时执行所有计算的代码:

以此为起点,我能够从StockhamFFT函数中提取旋转因子计算,并在编译时使用consteval函数执行它们。这是代码之后的样子:

这两个版本都是在 Ubuntu 19.10 上使用 gcc 10.0.1 编译的:

请注意,gcc 编译器是特别需要的,因为它是唯一constexpr支持sincos

“运行时”示例产生以下结果:

持续时间 292854 微秒。

“编译时”示例产生以下内容:

持续时间 295230 微秒。

编译时版本确实花费了更长的时间来编译,但不知何故仍然需要更长的时间来运行,即使大多数计算在程序开始之前就已经完成了!这怎么可能?我在这里遗漏了一些关键的东西吗?

0 投票
1 回答
365 浏览

c++ - `inline` 和 `noexcept` 在 consteval 上下文中是多余的吗?

我正在使用一些代码,其中constexpr使用了我目前consteval尽可能重构的函数。

据我了解,上面的inline关键字在函数中已经是多余的了constexpr

据我了解,noexcept关键字对于consteval函数来说是多余的,因为据我了解,它consteval必须在编译时进行评估,因此意味着 noexcept。这是真的还是我目前不考虑的事情(比如 constexpr exceptions)?

0 投票
1 回答
164 浏览

terminology - 用于描述在编译时已知但不为 constexpr 的 `consteval` 函数参数的名称

函数的参数consteval是:

  • 在编译时就知道
  • 不是 constexpr

Andrew Sutton 在他的论文翻译和评估:编译时元编程的心理模型中解释了这种行为背后的动机,正如这篇 SO 帖子所指出的那样。


您可以从consteval函数返回参数并将其用作constexpr

但是你不能constexpr在函数内部使用它consteval

上面无法编译,因为n不是a 。constexpr

您当然可以使用一个简单的 if,它将在编译时进行评估:


这是一个术语问题:

是否有一个在编译时已知不是常量表达式的常用名称?

0 投票
1 回答
216 浏览

c++ - 为什么立即函数默认不是 noexcept,为什么它们允许为 noexcept(false)?

从 c++20 开始,我们可以使用说明符定义立即函数consteval。当一个函数被声明consteval时,对该函数的每次调用都必须产生一个编译时常量,否则程序是错误的。此外,由于 c++20 的 try-catch 块在常量评估上下文中是允许的,但仍然不允许抛出异常。正因为如此,我最初认为这consteval意味着inline它也暗示noexcept,因为禁止抛出任何异常。正如您在这一点上可以想象的那样,这是不正确的:除非您指定noexcept,否则立即函数是一个潜在的抛出函数,其所有负面都由此派生。这是我不知道的原因吗?