15

这些可能应该在不同的问题中,但它们是相关的,所以......

  1. 为什么我们需要写作constexpr?鉴于一组限制,编译器不能评估代码以查看它是否满足constexpr要求,并将其视为满足要求constexpr吗?作为一个纯粹的文档关键字,我不确定它是否成立,因为我想不出我(其他人的constexpr函数的用户)应该真正关心它是否是运行时的情况。

    这是我的逻辑:如果它是一个昂贵的函数,我认为作为一个好的做法,无论我是否给它编译时常量输入,我都应该这样对待它。这可能意味着在加载时间调用它并保存结果,而不是在执行的关键点调用它。原因是因为constexpr实际上并不能向我保证它首先不会在运行时执行——所以也许应该有一个新的/不同的机制来做到这一点。

  2. 这些constexpr限制似乎将许多(如果不是大多数)函数排除在编译时评估之外,这在逻辑上可能是。我读过这至少部分(或可能全部?)以防止无限循环和挂起编译器。但是,如果这是原因,它是否合法?

对于使用给定输入的任何给定函数,编译器是否应该能够计算constexpr它是否无限循环?这并不能解决任何输入的停止问题。函数的输入是编译时间常数和有限的,因此编译器只需检查有限输入集的无限循环:实际使用的输入。如果您编写编译时无限循环,它应该是一个常规的编译错误。constexpr

4

3 回答 3

2

我问了一个非常相似的问题,为什么我们需要将函数标记为 constexpr?

我向Clang 的作者 Richard Smith 提问时,他解释说:

constexpr 关键字确实具有实用性。

它会影响何时实例化函数模板特化(如果在未评估的上下文中调用 constexpr 函数模板特化,则可能需要实例化它们;对于非 constexpr 函数而言,情况并非如此,因为对 one 的调用永远不能成为常量的一部分表达)。如果我们删除了关键字的含义,我们就必须尽早实例化更多的特化,以防调用碰巧是一个常量表达式。

它通过限制实现在翻译期间尝试评估所需的函数调用集来减少编译时间。(这对于需要实现来尝试常量表达式求值的上下文很重要,但如果这种求值失败也不是错误——尤其是静态存储持续时间的对象的初始化程序。)

这一切一开始似乎并不令人信服,但如果你仔细研究细节,事情就会在没有constexpr. 一个函数在被 ODR 使用之前不需要被实例化,这本质上意味着在运行时使用。函数的特殊之处constexpr在于它们可能违反此规则并且无论如何都需要实例化。

函数实例化是一个递归过程。实例化一个函数会导致它使用的函数和类的实例化,而不管任何特定调用的参数如何。

如果在实例化这个依赖树时出现问题(可能会付出巨大的代价),那么很难接受这个错误。此外,类模板实例化可能具有运行时副作用。

给定函数签名中依赖于参数的编译时函数调用,重载解析可能会导致函数定义的实例化,这仅仅是对重载集中的那些定义的辅助,包括甚至没有被调用的函数。这种实例化可能会产生副作用,包括格式错误和运行时行为。

可以肯定的是,这是一个极端情况,但如果您不要求人们选择加入功能,则可能会发生坏事constexpr

至于constexpr对象,某些类型可以生成核心常量表达式,无需声明即可在常量表达式上下文中使用constexpr。但是您并不真的希望编译器在编译时尝试评估每个表达式。这就是不断传播的目的。另一方面,在编译时记录何时需要发生某些事情似乎非常重要。

于 2013-11-07T08:00:28.173 回答
0

这一决定背后既有技术原因,也有意识形态原因。

  • 默认情况下,我们并不总是想要constexpr自己——这可能需要太多的编译时间。这是第一个。想象一下,您实现 isPrime了函数,并且传入了 100 个带有大 constexpr 值的调用。我认为您(在大多数情况下)不想让编译器再编译几分钟,因为它决定您在编译时需要这些值-时间本身。但如果确实如此 -constexpr手动指定修饰符。这增加了下一点:

  • 向后兼容性 - 假设每个将这个程序转换为 C++11 的可能的 C++98 程序作者都想要constexpr.

  • 第二点是决定函数是否可以单独constexpr 编译需要花费时间。如果它试图对每一个可能的功能都这样做,那将需要一些额外的时间开销。更重要的是,编译器通常无法确定给定函数是否可以是 constexpr ,所以你的第一个假设是不正确的。

于 2013-09-18T20:02:23.950 回答
0

[注意,我完全改变了我的答案]

要回答您的第二个问题,这里的编译器有两种情况:

  1. 编译器必须能够处理任意函数constexpr。在这种情况下,您仍然会遇到停止问题,因为输入集是constexpr函数和对它们的调用的所有组合。

  2. 编译器可以处理有限的一组constexpr函数。在这种情况下,编译器实际上可以确定某些程序是否会导致无限循环,而其他程序将无法编译(因为它们不在有效输入集中)。

因此,据推测,这些限制已经到位,以便在合理的编译器工作量下满足案例 2。

于 2013-09-18T16:33:57.543 回答