问题标签 [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.
c++ - 什么是 consteval?
显然,consteval
将成为 C++20 中的关键字。它的cppreference 页面当前是空白的。它将是什么以及它与它有什么关系constexpr
?
c++ - consteval 是否允许在函数参数上使用 static_assert?
目前,您不能使用static_assert
来验证函数的参数constexpr
,即使对它的所有调用确实都是constexpr
. 这是有道理的,因为编译器仍然必须创建此函数的非常量实例化,以防其他模块尝试调用它。可悲的是,即使该函数位于static
或位于匿名命名空间中也是如此。
然而,C++20 将引入一个新的关键字consteval
,类似于constexpr
但它不允许以非 constexpr 方式调用函数。在这种情况下,编译器可以确定函数参数在编译时总是已知的。因此,理论上应该可以用static_assert
.
问题是:标准允许吗?
例子:
我问是因为我要编写一些用户定义的文字(比示例更复杂)。我可以选择使用编译器扩展来处理验证,或者等待编译器更新并编写完全符合标准的代码。
c++ - 来自不同翻译单元的 consteval 函数会干扰吗?
我试图深入研究函数存在的含义inline
并偶然发现了这个问题。考虑这个小程序(演示):
在没有优化的情况下编译时,程序会产生以下输出:
这可能不是我们想要的,但至少我可以解释它。
- 编译器不需要
constexpr
在编译时计算函数的结果,因此它决定将其推迟到运行时。 constexpr
关于函数意味着inline
- 我们的
get()
函数碰巧有不同的实现 - 我们没有声明
get()
函数是静态的 get()
链接器必须只选择函数的一种实现
碰巧链接器选择了get()
from main.cpp
,它返回了 3。
现在到我不明白的部分。我只是将get()
功能从更改constexpr
为consteval
。现在编译器需要在编译期间计算值,即在链接时间之前(对吗?)。我希望get()
函数根本不存在于目标文件中。
但是当我运行它(演示)时,我有完全相同的输出!这怎么可能?.. 我的意思是,我知道这是未定义的行为,但这不是重点。为什么应该在编译时计算的值会干扰其他翻译单元?
UPD:我知道这个功能在 clang 中被列为未实现,但这个问题仍然适用。是否允许符合标准的编译器表现出这种行为?
c++ - 为什么 consteval 函数允许未定义的行为?
C++ 中的常量表达式有一个非常简洁的属性:它们的求值不能有未定义的行为(7.7.4.7):
表达式 e 是一个核心常量表达式,除非按照抽象机 ([intro.execution]) 的规则对 e 的求值将求值以下之一:
...
具有未定义行为的操作,如本文档的 [intro] 到 [cpp] [注:包括,例如,有符号整数溢出 ([expr.prop])、某些指针算术 ([expr.add])、除以零,或某些移位操作——尾注];
尝试将值存储13!
在 aconstexpr int
确实会产生一个很好的编译错误:
输出:
(顺便说一句,为什么错误说“调用'f(3)'”,而它是对f(13)的调用?..)
然后,我从 中删除constexpr
,x
但制作f
一个consteval
. 根据文档:
consteval - 指定一个函数是一个立即函数,也就是说,对函数的每次调用都必须产生一个编译时常量
我确实希望这样的程序会再次导致编译错误。但相反,该程序使用 UB 编译和运行。
这是为什么?
UPD:评论者建议这是一个编译器错误。我举报了:https ://bugs.llvm.org/show_bug.cgi?id=43714
c++ - 编译器是否允许在运行时调用立即(consteval)函数?
这可能是一个愚蠢的问题,但我很困惑。我有一种感觉,即在编译期间必须执行一个立即 ( )consteval
函数,而我们根本无法在二进制文件中看到它的主体。
这篇文章显然支持了我的感觉:
这意味着 [immediate] 函数仅在编译时可见。该函数不会发出符号,您无法获取此类函数的地址,并且调试器等工具将无法显示它们。在这个问题上,立即函数类似于宏。
在Herb Sutter 的出版物中可以找到类似的强烈主张:
请注意,C++20 草案已经包含了第一轮反射相关工作的一部分,这些工作将被纳入标准:保证在编译时运行的consteval 函数,它来自反射工作,专门设计用于操纵反射信息。
然而,有许多证据对这一事实并不十分清楚。
consteval - 指定一个函数是一个立即函数,也就是说,对函数的每次调用都必须产生一个编译时常量。
这并不意味着它只能在编译时调用。
来自P1073R3 提案:
现在普遍认为,未来语言对反射的支持应该使用 constexpr 函数,但由于“反射函数”通常必须在编译时进行评估,它们实际上很可能是即时函数。
似乎这意味着我的想法,但仍然没有说清楚。来自同一个提案:
然而,有时我们想表达一个函数在调用时(直接或间接)应该总是产生一个常量,而一个非常量的结果应该产生一个错误。
同样,这并不意味着函数必须仅在编译时进行评估。
从这个答案:
您的代码必须生成编译时常量表达式。但是编译时常量表达式在您使用它的上下文中不是可观察的属性,并且在链接甚至运行时执行它没有副作用!好像没有什么可以阻止
最后,有一个现场演示,其中consteval
函数在运行时被清楚地调用。但是,我希望这是因为consteval
在 clang 中还没有得到适当的支持,并且行为实际上是不正确的,就像在为什么 consteval 函数允许未定义的行为?
更准确地说,我想听听引用文章的以下哪些陈述是正确的:
- 立即函数仅在编译时可见(不能在运行时评估)
- 不为立即函数发出符号
- 调试器等工具将无法显示即时功能
c++ - 评估模板括号内的 constexpr
为什么以下将constexpr
积分注入模板不起作用
为什么不允许将明确constexpr
value
注入模板参数的限制?non-type
我不明白为什么会有这样的限制?consteval
那是不是因为尚未在其中实现clang-10
并衰减到...而无法编译constexpr
?
因为这有效:
c++ - 将计算从运行时转移到编译时如何使我的代码变慢?
我正在编写一个函数来使用 Stockham FFT 算法计算快速傅里叶变换,并发现如果 FFT 的长度是 2 的幂,则可以在编译时预先计算所有用于计算的“旋转因子”。
在 FFT 计算中,旋转因子计算通常占用总时间的很大一部分,因此理论上这样做应该会大大提高算法的性能。
昨天我花了一整天时间在一个新的编译器 (gcc 10) 上重新实现我的算法,这样我就可以使用 C++20consteval
功能在编译时预先计算所有的旋转因子。我成功地做到了,但最终在编译时预先计算所有旋转因子的代码实际上运行得更慢!
这是在运行时执行所有计算的代码:
以此为起点,我能够从StockhamFFT
函数中提取旋转因子计算,并在编译时使用consteval
函数执行它们。这是代码之后的样子:
这两个版本都是在 Ubuntu 19.10 上使用 gcc 10.0.1 编译的:
请注意,gcc 编译器是特别需要的,因为它是唯一constexpr
支持sin
和cos
“运行时”示例产生以下结果:
持续时间 292854 微秒。
“编译时”示例产生以下内容:
持续时间 295230 微秒。
编译时版本确实花费了更长的时间来编译,但不知何故仍然需要更长的时间来运行,即使大多数计算在程序开始之前就已经完成了!这怎么可能?我在这里遗漏了一些关键的东西吗?
c++ - `inline` 和 `noexcept` 在 consteval 上下文中是多余的吗?
我正在使用一些代码,其中constexpr
使用了我目前consteval
尽可能重构的函数。
据我了解,上面的inline
关键字在函数中已经是多余的了constexpr
。
据我了解,noexcept
关键字对于consteval
函数来说是多余的,因为据我了解,它consteval
必须在编译时进行评估,因此意味着 noexcept。这是真的还是我目前不考虑的事情(比如 constexpr exceptions
)?
terminology - 用于描述在编译时已知但不为 constexpr 的 `consteval` 函数参数的名称
函数的参数consteval
是:
- 在编译时就知道了
- 但不是 constexpr
Andrew Sutton 在他的论文翻译和评估:编译时元编程的心理模型中解释了这种行为背后的动机,正如这篇 SO 帖子所指出的那样。
您可以从consteval
函数返回参数并将其用作constexpr
:
但是你不能constexpr
在函数内部使用它consteval
:
上面无法编译,因为n不是a 。constexpr
您当然可以使用一个简单的 if,它将在编译时进行评估:
这是一个术语问题:
是否有一个在编译时已知但不是常量表达式的常用名称?
c++ - 为什么立即函数默认不是 noexcept,为什么它们允许为 noexcept(false)?
从 c++20 开始,我们可以使用说明符定义立即函数consteval
。当一个函数被声明consteval
时,对该函数的每次调用都必须产生一个编译时常量,否则程序是错误的。此外,由于 c++20 的 try-catch 块在常量评估上下文中是允许的,但仍然不允许抛出异常。正因为如此,我最初认为这consteval
意味着inline
它也暗示noexcept
,因为禁止抛出任何异常。正如您在这一点上可以想象的那样,这是不正确的:除非您指定noexcept
,否则立即函数是一个潜在的抛出函数,其所有负面都由此派生。这是我不知道的原因吗?