c++ - 编译器是否允许在运行时调用立即(consteval)函数?
问题描述
这可能是一个愚蠢的问题,但我很困惑。我有一种感觉,即在编译期间必须执行一个立即 ( )consteval
函数,而我们根本无法在二进制文件中看到它的主体。
这篇文章显然支持了我的感觉:
这意味着 [immediate] 函数仅在编译时可见。该函数不会发出符号,您无法获取此类函数的地址,并且调试器等工具将无法显示它们。在这个问题上,立即函数类似于宏。
在Herb Sutter 的出版物中可以找到类似的强烈主张:
请注意,C++20 草案已经包含了第一轮反射相关工作的一部分,这些工作将被纳入标准:保证在编译时运行的consteval 函数,它来自反射工作,专门设计用于操纵反射信息。
然而,有许多证据对这一事实并不十分清楚。
consteval - 指定一个函数是一个立即函数,也就是说,对函数的每次调用都必须产生一个编译时常量。
这并不意味着它只能在编译时调用。
来自P1073R3 提案:
现在普遍认为,未来语言对反射的支持应该使用 constexpr 函数,但由于“反射函数”通常必须在编译时进行评估,它们实际上很可能是即时函数。
似乎这意味着我的想法,但仍然没有说清楚。来自同一个提案:
然而,有时我们想表达一个函数在调用时(直接或间接)应该总是产生一个常量,而一个非常量的结果应该产生一个错误。
同样,这并不意味着函数必须仅在编译时进行评估。
从这个答案:
您的代码必须生成编译时常量表达式。但是编译时常量表达式在您使用它的上下文中不是可观察的属性,并且在链接甚至运行时执行它没有副作用!好像没有什么可以阻止
最后,有一个现场演示,其中consteval
函数在运行时被清楚地调用。但是,我希望这是因为consteval
在 clang 中还没有得到适当的支持,并且行为实际上是不正确的,就像在为什么 consteval 函数允许未定义的行为?
更准确地说,我想听听引用文章的以下哪些陈述是正确的:
- 立即函数仅在编译时可见(不能在运行时评估)
- 不为立即函数发出符号
- 调试器等工具将无法显示即时功能
解决方案
该提案提到:
该规范的一个结果是后端永远不需要看到即时函数。
因此,将调用替换为常量绝对是提案的意图。换句话说,常量表达式在翻译期间被评估。
但是,它并没有说它必须不被后端看到。事实上,在提案的另一句话中,它只是说不太可能:
这也意味着,与普通
constexpr
函数不同,consteval
函数不太可能出现在符号调试器中。
更一般地说,我们可以将问题重新陈述为:
编译器是否被迫评估常量表达式(无处不在;不仅仅是当他们确实需要它时)?
例如,如果一个常量表达式是数组元素的数量,编译器需要对其求值,因为它需要静态确定数组的总大小。
但是,编译器可能不需要评估其他用途,尽管任何体面的优化编译器都会尝试这样做,但这并不意味着它需要。
另一个需要考虑的有趣案例是解释器:虽然解释器仍然需要计算一些常量表达式,但它可能只是一直懒惰地做,而不执行任何常量折叠。
因此,据我所知,它们不是必需的,但我不知道我们需要从标准中得到确切的引用来证明它(或以其他方式)。也许这本身就是一个很好的后续问题,它也可以回答这个问题。
例如,在[expr.const]p1中有一条注释说它们可以,而不是它们:
[注意:常量表达式可以在翻译过程中求值。——尾注]
推荐阅读
- javascript - React Hooks:在useEffect警告中获取数据
- java - Android 支持库不存在但无法编辑“Build”文件夹下的文件以引用 Android X
- laravel - 拉拉维尔。让用户使用不唯一的电子邮件登录
- reactjs - 动态“onOutsideClick”的useRef挂钩?
- xml - 如何将 XML 转换为 UTF-8 并保留标头
- r - 在 2D 平面中计算从点到点的罗盘航向
- jooq - jOOQ、Pojos 和数据库优先设计
- python - 我的代码读取此 csv 文件并将第一列命名为“团队”时遇到问题
- c# - 从通用项目工厂返回的随机项目(加权)
- arrays - 熊猫数据框列以二维数组的形式出现,其中包含引号