c++ - return 语句中的 C++ constexpr 函数
问题描述
为什么 constexpr 函数在编译时不求值,但在运行时在 main 函数的 return 语句中求值?
它试过了
template<int x>
constexpr int fac() {
return fac<x - 1>() * x;
}
template<>
constexpr int fac<1>() {
return 1;
}
int main() {
const int x = fac<3>();
return x;
}
结果是
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 6
mov eax, 6
pop rbp
ret
使用 gcc 8.2。但是当我在return语句中调用函数时
template<int x>
constexpr int fac() {
return fac<x - 1>() * x;
}
template<>
constexpr int fac<1>() {
return 1;
}
int main() {
return fac<3>();
}
我明白了
int fac<1>():
push rbp
mov rbp, rsp
mov eax, 1
pop rbp
ret
main:
push rbp
mov rbp, rsp
call int fac<3>()
nop
pop rbp
ret
int fac<2>():
push rbp
mov rbp, rsp
call int fac<1>()
add eax, eax
pop rbp
ret
int fac<3>():
push rbp
mov rbp, rsp
call int fac<2>()
mov edx, eax
mov eax, edx
add eax, eax
add eax, edx
pop rbp
ret
为什么在编译时评估第一个代码而在运行时评估第二个代码?
我还用 clang 7.0.0 尝试了这两个片段,并在运行时对其进行评估。为什么这对 clang 无效 constexpr?
所有评估都是在 Godbolt 编译器资源管理器中完成的。
解决方案
一个常见的误解constexpr
是它的意思是“这将在编译时进行评估” 1。
它不是。constexpr
引入的目的是让我们编写可以在需要它们的上下文中生成常量表达式的自然代码。这意味着“这必须在编译时可评估”,这是编译器将检查的内容。
因此,如果您编写了一个constexpr
返回 int 的函数,您可以使用它来计算模板参数、变量的初始constexpr
值设定项(const
如果它是整数类型)或数组大小。您可以使用该函数来获得自然的、声明性的、可读的代码,而不是过去需要求助于旧的元编程技巧。
但是constexpr
函数仍然是常规函数。说明constexpr
符并不意味着编译器有2来优化它以在编译时进行常量折叠。最好不要因为这样的提示而混淆它。
1 - 感谢user463035818的措辞。
2 - c ++ 20,consteval
但是是一个不同的故事:)
推荐阅读
- oracle - 由于会话状态值导致的 Oracle Apex 性能问题
- hadoop - 如何调试 map-reduce 失败的地方?
- javascript - 如何遍历多个相似元素并依次更改每个元素的属性?
- optimization - 优化 Pywinauto
- python - 如何在 Python 中切换嵌套字典的值和键?
- sql - 日期字符串中使用的日期格式是什么,“2019-01-21T19:02:25Z”
- python - 尝试定义线程时对象没有属性
- php - 使用 PHP 函数 end() 时间接修改 Illuminate\Support\Collection 的重载元素无效
- c# - 如何从字典中获取不匹配的列表
- wordpress - Woocommerce 和 WP-Rocket 缓存的 Facebook Pixel 问题