首页 > 解决方案 > 编译器是否允许在运行时调用立即(consteval)函数?

问题描述

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

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

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

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

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

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

cppreference

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

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

来自P1073R3 提案

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

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

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

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

这个答案

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

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

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

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

标签: c++language-lawyerc++20consteval

解决方案


该提案提到:

该规范的一个结果是后端永远不需要看到即时函数。

因此,将调用替换为常量绝对是提案的意图。换句话说,常量表达式在翻译期间被评估。

但是,它并没有说它必须不被后端看到。事实上,在提案的另一句话中,它只是说不太可能:

这也意味着,与普通constexpr函数不同,consteval函数不太可能出现在符号调试器中。


更一般地说,我们可以将问题重新陈述为:

编译器是否被迫评估常量表达式(无处不在;不仅仅是当他们确实需要它时)?

例如,如果一个常量表达式是数组元素的数量,编译器需要对其求值,因为它需要静态确定数组的总大小。

但是,编译器可能不需要评估其他用途,尽管任何体面的优化编译器都会尝试这样做,但这并不意味着它需要。

另一个需要考虑的有趣案例是解释器:虽然解释器仍然需要计算一些常量表达式,但它可能只是一直懒惰地做,而不执行任何常量折叠。

因此,据我所知,它们不是必需的,但我不知道我们需要从标准中得到确切的引用来证明它(或以其他方式)。也许这本身就是一个很好的后续问题,它也可以回答这个问题。

例如,在[expr.const]p1中有一条注释说它们可以,而不是它们:

[注意:常量表达式可以在翻译过程中求值。——尾注]


推荐阅读