如果编译器只能执行恒定折叠,则是毫无意义的
Is constexpr pointless if the compiler can just perform constant folding?
谢谢,我不需要任何书来教我constexpr
的含义。我正在教constexpr
,我的简单示例失败了说服学生为什么他们应该通过constexpr
来使用编译时间计算的优势。
也请严格避免链接到没有装配代码或分析的问题,它们对我的问题毫无意义。
我正在寻找一个示例,以说明为什么constexpr
根本有用,并且不能被解散。
好吧,在许多情况下,如果constexpr
被const
取代,那么实际上没有任何错误。因此,我设计了以下示例:
main_const.cpp
#include <iostream>
using namespace std;
const int factorial(int N)
{
if(N<=1)
return 1;
else
return N*factorial(N-1);
}
int main()
{
cout<<factorial(10)<<endl;
return 0;
}
和
main_constexpr.cpp
#include <iostream>
using namespace std;
constexpr int factorial(int N)
{
if(N<=1)
return 1;
else
return N*factorial(N-1);
}
int main()
{
cout<<factorial(10)<<endl;
return 0;
}
但问题是对于他们来说,汇编代码为
main_const.asm
12:main_last.cpp **** int main()
13:main_last.cpp **** {
132 .loc 1 13 0
133 .cfi_startproc
134 0000 4883EC08 subq $8, %rsp
135 .cfi_def_cfa_offset 16
14:main_last.cpp **** cout<<factorial(10)<<endl;
136 .loc 1 14 0
137 0004 BE005F37 movl $3628800, %esi
137 00
138 0009 BF000000 movl $_ZSt4cout, %edi
138 00
139 000e E8000000 call _ZNSolsEi
对于后一个,它是
main_constexpr.asm
12:main_now.cpp **** int main()
13:main_now.cpp **** {
11 .loc 1 13 0
12 .cfi_startproc
13 0000 4883EC08 subq $8, %rsp
14 .cfi_def_cfa_offset 16
14:main_now.cpp **** cout<<factorial(10)<<endl;
15 .loc 1 14 0
16 0004 BE005F37 movl $3628800, %esi
16 00
17 0009 BF000000 movl $_ZSt4cout, %edi
17 00
18 000e E8000000 call _ZNSolsEi
18 00
这意味着编译器显然已经使用cosnt
或constexpr
进行了(10!) = 3628800
的恒定折叠。
汇编是通过
进行的g++ -O3 -std=c++17 -Wa,-adhln -g main.cpp>main.asm
尽管在大多数情况下,许多人都认为该代码现在没有进行任何调查,因为编译器很聪明,我想知道constexpr
背后是否有任何真实,诚实和有意义的优化好处?
对于优化的 sole目的,不可能构造 constexpr
表达式/函数调用序列,该序列是不可能的编译器以优化非constexpr
等效的编译器。当然,这是因为constexpr
对其使用有许多要求。任何constexpr
代码都必须与该翻译单元的编译器进行内衬和可见。递归通过所有导致constexpr
值产生的表达式。
同样,constexpr
函数不允许执行诸如分配内存(尚未分配(,进行低级功能指针操作(尚未(,调用非constexpr
功能以及其他可以阻止编译器能够能够能够能够保持的事情在编译时执行它们。
因此,如果您具有constexpr
构造,则等效的非constexpr
版本将具有其实现的所有这些相同属性。而且,由于编译器必须能够在编译时执行constexpr
代码,因此至少必须在理论上能够对非constexpr
等效执行相同的操作。
在任何特定情况下它是否确实优化它是无关紧要的;每个编译器版本都会发生这种变化。它可以足够的事实。
您的问题是您相信constexpr
的主要目的是性能。这是对允许您无法做的事情进行的优化。
constexpr
在性能中的作用主要是,通过将函数或变量标记为constexpr
,编译器可以防止您执行实现可能无法在编译时执行的事情。如果您想跨平台进行编译时执行,则必须保持在编译时执行的标准定义边界内。
语法意味着编译器会积极阻止您做非constexpr
的事情。您不能意外编写无法在编译时运行的代码。
也就是说,您应该查看的问题不是如果没有它,constexpr
代码是否可以以相同的方式编写。这是您是否会以constexpr
的方式编写代码,而没有关键字。对于任何复杂性系统,答案越来越多地接近"否",如果没有其他原因,则很容易意外地执行编译器无法在编译时运行的事情。
您必须在constexpr表达式中使用它来强制编译时间评估:
int main()
{
constexpr int fact_10 = factorial(10); // 3628800
std::cout << fact_10 << std::endl;
return 0;
}
否则您依靠编译器优化。
此外,constexpr允许其使用,而简单的const不允许:
所以假设:
constexpr int const_expr_factorial(int) {/*..*/}
int factorial(int) {/*..*/}
您有:
char buffer[const_expr_factorial(5)]; // OK
char buffer[factorial(5)]; // KO, might compile due to VLA extension
std::integral_constant<int, const_expr_factorial(10)> fact_10; // OK
std::integral_constant<int, factorial(10)> fact_10; // KO
- 正在折叠转发引用
- 在 2D 向量中使用第三个 [ ] 有什么意义?
- 带有用户定义类的c++折叠表达式
- C++如果必须在编译时确定大小,std::array 有什么意义?
- 在C++中,使用带有 std::optional 参数的函数<T>来表示可选参数是否有意义?
- "std::make_optional"的意义何在
- 当我从下面的代码中删除关键字 virtual 时,它可以正常工作,否则会出现错误。在这里"virtual"字的意义是什么?
- 深度值没有意义 R200 相机
- 叮当声:折叠表情和"expression result unused"警告
- 函数重载毫无意义吗
- x86 - 为什么编译器在下一条指令中插入看似毫无意义的JMP?
- OpenGL 中的动态加载着色器毫无意义吗?
- 如果编译器只能执行恒定折叠,则是毫无意义的
- 在同一调用中打印 %n 的值 - 毫无意义?
- Netbeans 中的C++:许多毫无意义的"unexpected token"提示
- C++结构 - 毫无意义?
- 我收到"无效类型 int[int]...",但这毫无意义
- 常量工会成员有什么用?他们不是毫无意义吗?
- 将函数的返回类型声明为 T&&& 是否毫无意义?
- CUDAMemcpy对我来说毫无意义…为什么要在普通c++中指定设备内存?