6

据我了解, constexpr 可以被视为对编译器的提示,以检查是否可以在编译时评估给定的表达式,并在可能的情况下这样做。

我知道它还对声明为 constexpr 的函数或初始化施加了一些限制,但最终目标是编译时评估,不是吗?

所以我的问题是,为什么我们不能把它留给编译器呢?它显然能够检查前置条件,那么为什么它不对每个表达式执行并尽可能在编译时进行评估呢?

关于为什么会出现这种情况,我有两个想法,但我还不相信他们能做到这一点:

a) 在编译期间可能需要很长时间。

b)由于我的代码可以在不允许使用 normale 函数的位置使用 constexpr 函数,因此说明符也是声明的一部分。如果编译器自己完成所有操作,则可以在 C 数组定义中使用具有该函数的一个版本的函数,但在下一个版本中可能会出现编译器错误,因为编译时评估的先决条件是不更满意。

4

4 回答 4

5

constexpr不是对编译器的任何“提示”;constexpr是一个要求。它不需要在编译时实际执行表达式;它要求它可以

什么constexpr(对于函数)限制了您可以放入函数定义中的内容,以便编译器可以在编译时尽可能轻松地执行该代码。这是程序员和编译器之间的合同。如果你的函数违反合约,编译器会立即出错。

建立合约后,您现在可以constexpr在语言需要编译时常量表达式的地方使用这些函数。然后编译器可以检查常量表达式的元素以查看表达式调用constexpr函数中的所有函数调用;如果他们不这样做,则会再次导致编译器错误。

您试图使这一点隐含会导致两个问题。首先,如果没有语言定义的明确契约,我怎么知道我可以在constexpr函数中做什么和不能做什么?我怎么知道什么会使函数不constexpr成立?

其次,如果合同不在编译器中,通过声明我要创建函数的意图,constexpr编译器将如何验证我的函数是否符合该合同?它不能;constexpr在我发现它实际上不是一个正确的函数之前,它必须等到我在常量表达式中使用它。

最好事先明确说明合同。

于 2013-07-15T18:16:20.860 回答
3

constexpr 可以看作是提示编译器检查是否可以在编译时评估给定的表达式,并在可能的情况下这样做

不,见下文

最终目标是编译时评估

不,见下文。

那么为什么它不对每个表达式执行并尽可能在编译时进行评估呢?

优化器会按照 as-if 规则执行类似的操作。

constexpr不用于使事情变得更快,它用于允许在运行时变量表达式非法的上下文中使用结果。

于 2013-07-15T18:22:43.560 回答
2

这只是我的评估,但我相信您的 (b) 理由是正确的(它构成了编译器可以强制执行的接口的一部分)。接口要求既适用于代码的编写者,也适用于代码的客户端。

作者可能打算在编译时上下文中使用某些东西,但实际上并没有以这种方式使用它。如果作者违反了 的规则constexpr,他们可能直到发布后才发现尝试使用它的客户constexpr失败。或者,更现实地,库可能在constexpr某种意义上使用版本 1 中的代码,在版本 2 中重构这种用法,并constexpr在版本 3 中破坏兼容性而没有意识到这一点。通过检查constexpr-compliance,将在部署之前捕获版本 3 中的损坏。

客户端的界面更加明显——内联函数不会默默地成为constexpr必需的,因为它碰巧工作并且有人以这种方式使用。

我不相信您的(a)原因(编译器可能需要太长时间)是适用的,因为(1)编译器必须在constexpr标记代码时检查大部分约束,(2)没有注释,编译器只需要在以某种constexpr方式使用时进行检查(因此不必检查大多数函数,并且(3)IIUC D编程语言实际上确实允许在满足要求时对函数进行编译时评估没有任何申报协助,所以显然可以做到。

于 2013-07-15T18:06:36.423 回答
0

我想我记得看过 Bjarne Stroustrup 的早期演讲,他提到程序员希望对这个“危险”功能进行细粒度控制,据我了解,他们不希望在编译时“意外”执行某些事情而他们不知道。(即使这听起来是件好事。)

这可能有很多原因,但唯一有效的原因是我认为最终的编译速度((a)在你的列表中)。如果每个函数都可以在编译时计算,编译器会承担太多的负担。随着编译时间的普遍下降,这个论点变得更弱了。

像 C++ 的许多其他特性一样,最终发生的是我们最终得到了“错误的默认值”。所以你必须告诉你什么时候想要constexpr而不是什么时候不想要constexprruntimeexpr);你必须告诉你什么时候想要而不是你想要const的地方mutable等等。

诚然,您可以想象在编译时需要花费大量时间才能运行并且在运行时无法摊销(使用其他类型的机器资源)的函数。(我不知道“超时”可能是编译器中的一个标准constexpr,但它可能是这样。)或者它可能是在一个总是期望在有限时间内完成编译的系统中编译,但是无界运行时是可接受的(或可调试的)。

constexpr我知道这个问题已经过时了,但时间已经表明,将其设为默认值实际上是有意义的:

例如,在 C++17 中,您可以声明一个 lambda constexpr,但更重要的是constexpr,如果可以的话,它们是默认的。

https://docs.microsoft.com/en-us/cpp/cpp/lambda-expressions-constexpr

请注意,lambda 具有所有“正确”(相反的)默认值,成员(捕获)是const默认的,参数是默认的模板auto,现在这些函数是constexpr默认的。

于 2021-01-16T04:29:19.850 回答