为什么constexpr在适用时不暗示?

时间:2013-09-18 16:02:02

标签: c++ c++11 constexpr

这些应该是在不同的问题,但它们是相关的......

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

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

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

  3. 对于使用给定输入的任何给定constexpr函数,编译器是否应该能够计算它是否无限循环?这正在解决任何输入的halting problemconstexpr函数的输入是编译时常量和有限的,因此编译器只需检查有限输入集的无限循环:实际使用的输入。 如果编写编译时无限循环,则应该是常规编译错误。

3 个答案:

答案 0 :(得分:2)

我问了一个非常相似的问题,Why do we need to mark functions as constexpr?

I pressed Clang作者理查德史密斯解释:

  

constexpr关键字确实有效用。

     

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

     

通过限制在翻译期间尝试评估所需的实现的函数调用集,减少了编译时间。 (这对于需要实现以进行常量表达式评估的上下文很重要,但如果此类评估失败则不是错误 - 特别是静态存储持续时间对象的初始化器。)

这一切看起来并不令人信服,但如果你仔细研究细节,那么事情就会在没有constexpr的情况下解开。在使用ODR之前,不需要实例化函数,这实际上意味着在运行时使用。 constexpr函数的特殊之处在于它们可以违反此规则并且无论如何都需要实例化。

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

如果在实例化此依赖关系树时出现问题(可能花费很大),则很难吞下错误。此外,类模板实例化可能会产生运行时副作用。

给定函数签名中依赖于参数的编译时函数调用,重载解析可能会导致函数定义的实例化仅仅是辅助过载集中的函数定义,包括甚至不被调用的函数。此类实例化可能具有副作用,包括不良形式和运行时行为。

这是一个确定的角落案例,但如果您不要求人们选择加入constexpr函数,就会发生不好的事情。

对于constexpr个对象,某些类型可以生成核心常量表达式,它们可以在常量表达式上下文中使用,而无需声明constexpr。但是你真的不希望编译器在编译时尝试评估每个表达式。这就是恒定传播的目的。另一方面,在编译时记录需要的内容似乎非常重要。

答案 1 :(得分:0)

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

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

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

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

  3. 因此可能存在限制,以便在合理数量的编译器工作量下满足案例2。

答案 2 :(得分:0)

这一决定背后有技术和意识形态的原因。

  • 默认情况下,我们并不总是想要constexpr - 它可能需要 编译时间过多。那是第一次。想象一下你实施了 isPrime功能,你有100个大constexpr电话 传入的值。我认为你没有(在大多数情况下)想要制作 编译器将其编译几分钟,因为它 决定在编译时自己需要这些值。但如果 确实如此 - 手动指定constexpr修饰符。这增加了下一点:

  • 向后兼容 - 这是不明智的假设每个可能的C ++ 98程序作者谁转换该程序C ++ 11个欲望constexpr

  • 第二点是确定函数是否可以constexpr 将自己编译时间。如果它试图为每个可能的功能执行此操作,则需要一些额外的时间开销。更多,经常是编译器 无法决定给定的功能是否可以是constexpr,所以 你的第一个假设是不正确的。

相关问题