任何只包含return语句的函数都可以声明为constexpr
,因此,如果所有参数都为constexpr
,并且在其主体中只调用constexpr
函数,则可以在编译时进行求值。是否有任何理由不声明constexpr
constexpr
示例:
constexpr int sum(int x, int y) { return x + y; }
constexpr i = 10;
static_assert(sum(i, 13) == 23, "sum correct");
谁能提供一个例子,说明在constexpr
中声明一个函数会有什么危害?
一些最初的想法:
即使没有很好的理由声明一个函数不是constexpr
,我也可以想象constexpr
关键字有一个过渡角色:在不需要编译时求值的代码中没有它,将允许没有实现编译时求值的编译器仍然编译该代码(但是在需要它们的代码上可靠地失败,正如使用constexpr
所明确说明的那样)。
但我不明白的是:如果没有充分的理由声明一个函数不是constexpr
,为什么标准库中的每个函数都不声明constexpr
?(您不能争辩说它还没有完成,因为还没有足够的时间来完成它,因为为所有人做它是不需要动脑筋的--而不是决定每个单独的函数是否让它成为constexpr
。)-我知道N2976故意不为许多标准库类型(如容器)要求cstrs,因为这对于可能的实现来说太有限了。让我们从参数中排除它们,并想知道:一旦标准库中的类型实际具有cstr,为什么在其上操作的每个函数都不声明为constexpr
在大多数情况下,您也不能因为没有设想任何编译时用法而不喜欢声明函数constexpr
:因为如果其他人使用您的代码,他们可能会看到您没有看到的用法。(当然,对于类型特征类型和类似的东西也是如此。)
所以我猜一定有一个很好的理由和一个很好的例子来刻意不声明函数constexpr
(说到“每个函数”,我的意思总是:每个满足返回值要求的函数都被定义为一个constexpr
语句,只接受constexpr cstrs类型的参数,并且只调用constexpr
函数。由于C++14,much more is allowed in the body of such function:例如,C++14常量表达式函数可以使用局部变量和循环,因此可以将更广泛的函数类声明为constexpr
。)
问题Why does std::forward
discard constexpr
-ness?是这个问题的一个特例。
发布于 2011-02-25 18:59:17
只有遵守constexpr
规则的函数才能被声明为constexpr
-没有动态转换,没有内存分配,没有对非constexpr
函数的调用,等等。
将标准库中的函数声明为constexpr
要求所有实现都遵循这些规则。
首先,这需要检查每个函数是否可以实现为constexpr
,这是一项很长的工作。
其次,这是对实现的一个很大的限制,并将宣布许多调试实现为非法。因此,只有当收益大于成本,或者需求足够严格,以至于实现几乎必须遵守constexpr
规则时,它才是值得的。对每个函数进行这种评估也是一项漫长的工作。
发布于 2011-02-25 12:29:42
我想你指的是partial evaluation。你所触及的是,一些程序可以被分成两部分-一部分需要运行时信息,另一部分可以在没有任何运行时信息的情况下完成-理论上,在开始运行程序之前,你可以完全评估程序中不需要任何运行时信息的部分。有一些编程语言可以做到这一点。例如,D编程语言在编译器中内置了一个解释器,它允许您在编译时执行代码,前提是它满足某些限制。
让部分求值起作用有几个主要的挑战。首先,它极大地复杂化了编译器的逻辑,因为编译器需要能够模拟在编译时可以放入可执行程序中的所有操作。在最坏的情况下,这需要您在编译器中有一个完整的解释器,这使得一个困难的问题(编写一个好的C++编译器)变得更加困难。
我认为目前关于constexpr
规范的原因只是为了限制编译器的复杂性。它所限定的案例非常容易检查。没有必要在编译器中实现循环(这可能会导致一系列其他问题,比如在编译器中执行无限循环会发生什么情况)。它还避免了编译器潜在地必须计算可能在运行时导致段错误的语句,例如跟随错误的指针。
另一个要记住的注意事项是,有些函数有副作用,例如从cin
读取或打开网络连接。像这样的函数基本上不能在编译时优化,因为这样做需要只有在运行时才能获得的知识。
总而言之,理论上没有理由不能在编译时对C++程序进行部分评估。事实上,人们一直都在这样做。例如,优化编译器本质上就是试图尽可能多地做到这一点的程序。模板元编程是C++程序员尝试在编译器中执行代码的一个实例,使用模板可以做一些很棒的事情,部分原因是模板的规则形成了一种函数式语言,编译器更容易实现这种语言。此外,如果您考虑到编译器编写时间和编程时间之间的权衡,模板元编程表明,如果您可以让程序员不遗余力地获得他们想要的东西,您可以构建一种非常弱的语言(模板系统),并使语言复杂性保持简单。(我说的“弱”是指“不是特别有表现力的”,而不是可计算性理论意义上的“弱”)。
希望这能有所帮助!
发布于 2011-02-25 13:15:42
如果该函数有副作用,则不希望将其标记为constexpr
。Example
我不能从中得到任何意想不到的结果,实际上它看起来像gcc 4.5.1 just ignores constexpr
https://stackoverflow.com/questions/5112305
复制相似问题