这可能是一个愚蠢的问题,但是我很困惑。我有一个感觉,立即(consteval
)函数必须在编译时执行,而我们根本看不到二进制代码中的主体。
This article显然支持我的感觉:
这意味着[immediate]函数仅在编译时可见。该函数不会发出符号,您不能使用该函数的地址,并且调试器之类的工具将无法显示它们。在这种情况下,立即函数类似于宏。
在Herb Sutter's publication中可以找到类似的强项:
请注意,C ++ 20草案已经包含了第一轮与反射相关的工作,并将其纳入该标准:约束函数保证在编译时运行,这些函数来自反射工作,并且专门用于处理反射信息。
但是,有很多证据对此事实不太清楚。
来自cppreference:
consteval-指定一个函数为立即函数,也就是说,对该函数的每次调用都必须产生一个编译时常量。
这并不意味着它仅在编译时被调用。
现在已经普遍同意,将来对反射的语言支持应该使用constexpr函数,但是由于通常在编译时对“反射函数”进行评估,因此它们实际上很可能是立即函数。
看起来这就是我的想法,但仍然不清楚。来自同一提议:
但是,有时我们想表达的是,函数在被调用时(直接或间接)应始终产生一个常数,而非常数结果应产生一个错误。
同样,这并不意味着必须在编译时评估函数。
来自this answer:
您的代码必须产生一个编译时间常数表达式。但是,在您使用编译时常数表达式的上下文中,它不是可观察的属性,并且在链接或甚至运行时时也没有副作用!在没有什么可以阻止的情况下
最后是there is a live demo,其中在运行时明确调用了consteval
函数。但是,我希望这是由于consteval
尚未在clang中得到正确支持,并且该行为实际上是不正确的,就像Why does a consteval function allow undefined behavior?
更准确地说,我想听听被引用文章的以下哪些陈述是正确的:
答案 0 :(得分:5)
该提案提到:
此规范的一个后果是,立即函数不必在后端看到。
因此提案的意图肯定是用常量代替了调用。换句话说,常量表达式是在翻译过程中求值的。
但是,它并不表示要求后端不可见。实际上,在提案的另一句话中,它只是说不太可能:
这也意味着,与普通的
constexpr
函数不同,consteval
函数不太可能出现在符号调试器中。
更一般地说,我们可以将问题重新陈述为:
编译器是否被迫对常量表达式求值(在任何地方;不仅仅是在确实需要时)?
例如,如果编译器是数组的元素数量,则编译器需要评估一个常量表达式,因为它需要静态确定数组的总大小。
但是,编译器可能不需要评估其他用途,尽管任何体面的优化编译器都会尝试这样做,但这并不意味着它需要这样做。
另一个值得考虑的有趣案例是解释器:尽管解释器仍需要评估某些常量表达式,但它可能一直懒惰地执行它,而无需执行任何常量折叠。
据我所知,它们不是必需的,但我不知道我们需要从标准中证明(或以其他方式)的确切报价。也许这本身就是一个很好的后续问题,也可以回答这个问题。
例如,在[expr.const]p1中有一条说明说可以,而不是说:
[注意:常量表达式可以在翻译过程中求值。 —尾注]
答案 1 :(得分:3)
更准确地说,我想听听被引用文章的以下哪些陈述是正确的:
- 立即函数仅在编译时可见(并且无法在运行时评估)
- 不为立即函数发出符号
- 诸如调试器之类的工具将无法显示即时功能
这些几乎都不是C ++标准可以给出的答案。该标准未定义“符号”或工具可以显示的内容。就标准而言,几乎所有这些都是经销商的选择。
实际上,即使是“编译时间”与“运行时间”的问题也是该标准都没有解决的问题。与标准有关的唯一问题是某物是否为常量表达式。调用constexpr
函数 可能会产生一个常数表达式,具体取决于其参数。以不产生常量表达式的方式调用consteval
函数是不正确的。
标准所做的定义是“看到”的内容。尽管这与“编译时间”无关。当前的C ++ 20草案中有许多语句禁止大多数函数处理对立即函数的指针/引用。例如,N4835(C ++ 20的最新工作草案)在[expr.prim.id] / 3中声明:
表示立即函数的id表达式应仅出现
作为立即调用的子表达式,或者
在立即函数上下文中。
因此,如果您不在立即函数中,或者没有使用即时函数的名称来调用另一个即时函数(将指针/对该函数的引用传递),则无法命名即时函数。而且,如果不命名该函数,就无法获得指向该函数的指针/引用。
规范中的此语句和其他语句(例如pointers to immediate function not being valid results of constant expressions)基本上使指向立即函数的指针/引用不可能泄漏到常量表达式之外。
因此,有关立即函数可见性的声明在某种程度上是正确的。可以为立即函数发出符号 ,但是您不能以防止丢弃该符号的方式使用立即函数。
consteval
基本上就是这样。它不使用标准语言来强制执行必须发生的事情。它使用标准语言来使得不可能以防止发生的方式使用该功能。所以说:
不能使用立即函数来阻止编译器在编译时执行它。
您不能以阻止编译器为其丢弃符号的方式使用立即函数。
您不能以强制调试器能够看到它们的方式使用立即函数。
实施质量有望从那里得到好处。
还应注意,调试版本用于...调试。高级编译器工具能够调试生成常量表达式的代码是完全合理的。因此,可以看到立即执行功能的调试器是一项完全理想的技术。随着编译时代码变得越来越复杂,这一点变得越来越重要。