我有什么保证可能在编译时评估可能包含constexpr函数调用的核心常量表达式(如[expr.const] .2中所示),并且这取决于哪些条件? ?
constexpr
隐含地承诺通过将计算移至转换阶段(编译时)来改善运行时性能。这两点似乎彼此矛盾。
在哪种情况下,编译器可以依靠解析核心常量表达式(其中可能包含任意复杂的计算),而不是将其推迟到运行时?
至少在-O0
下,gcc似乎实际上在发出代码并调用constexpr函数。在-O1
下并没有。
我们是否必须像这样使用trickery来迫使constexpr通过模板系统:
template <auto V>
struct compile_time_h { static constexpr auto value = V; };
template <auto V>
inline constexpr auto compile_time = compile_time_h<V>::value;
constexpr int f(int x) { return x; }
int main() {
for (int x = 0; x < compile_time<f(42)>; ++x) {}
}
答案 0 :(得分:7)
调用constexpr
函数并将输出分配给constexpr
变量时,它将始终在编译时运行。
这是一个最小的例子:
// Compile with -std=c++14 or later
constexpr int fib(int n) {
int f0 = 0;
int f1 = 1;
for(int i = 0; i < n; i++) {
int hold = f0 + f1;
f0 = f1;
f1 = hold;
}
return f0;
}
int main() {
constexpr int blarg = fib(10);
return blarg;
}
在-O0
编译时,gcc为main
输出以下程序集:
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 55
mov eax, 55
pop rbp
ret
尽管所有优化均已关闭,但fib
函数本身从未调用过main
。
这适用于一直返回到C++11
的情况,但是在C ++ 11中,必须重写fib
函数以使用转换,以避免使用可变变量。
为什么编译器有时在可执行文件中包含fib
的程序集?在运行时以及何时使用constexpr
函数 在运行时调用它的行为将类似于常规函数。
正确使用constexpr
可以在特定情况下提供一些性能上的好处,但是推动一切constexpr
的努力更多是关于编写代码,编译器可以检查未定义的行为。
constexpr
提供性能优势的例子是什么?在实现std::visit
之类的功能时,您需要创建一个函数指针查找表。每次调用std::visit
时创建查找表的开销很大,并且将查找表分配给static
局部变量仍然会导致可衡量的开销,因为程序每次都要检查该变量是否已初始化该功能运行。
非常感谢,您可以制作查询表constexpr
,编译器实际上会将查询表内联到该函数的汇编代码中 ,这样,查询表的内容就变得很重要了。运行std::visit
时更有可能位于指令缓存中。
C ++ 20是否提供任何机制来保证某些内容在编译时运行?
如果函数为consteval
,则标准指定每次对该函数的调用都必须产生一个编译时常数。
这可用于强制对任何constexpr函数进行编译时评估:
template<class T>
consteval T run_at_compiletime(T value) {
return value;
}
作为参数run_at_compiletime
给出的任何内容都必须在编译时进行评估:
constexpr int fib(int n) {
int f0 = 0;
int f1 = 1;
for(int i = 0; i < n; i++) {
int hold = f0 + f1;
f0 = f1;
f1 = hold;
}
return f0;
}
int main() {
// fib(10) will definitely run at compile time
return run_at_compiletime(fib(10));
}
答案 1 :(得分:4)
从不; C ++标准几乎允许整个编译在“运行时”进行。某些诊断必须在编译时完成,但是没有什么可以防止编译器方面的精神错乱。
您的二进制文件可能是附加了您的源代码的编译器的副本,而C ++不会说编译器做错了任何事情。
您正在查看的是QoI-插图质量-问题。
实际上,constexpr
变量往往是在编译时计算的,而模板参数总是在编译时计算的。
consteval
也可以用于标记功能。