想知道以下是否让任何人感到惊讶,就像我一样? Alex Allain关于使用constexpr的文章here显示了以下因子示例:
constexpr factorial (int n)
{
return n > 0 ? n * factorial( n - 1 ) : 1;
}
并声明:
现在你可以使用factorial(2),当编译器看到它时,它可以 优化掉调用并在编译时完全进行计算 时间。
我在VS2015中在发布模式下尝试了这一点,并在(/ Ox)上进行了全面优化,并在调试器中查看了程序集,并看到在编译时没有的因子计算。 / p>
使用GCC v5.4.0和--std = C ++ 14,我必须在编译时执行计算之前使用/ O2或/ O3。我很惊讶,在编译时没有使用/ O计算。
主要问题是:为什么VS2015在编译时没有执行此计算?
答案 0 :(得分:5)
这取决于函数调用的上下文。
例如,以下显然永远无法在编译时计算:
int x;
std::cin >> x;
std::cout << factorial(x);
另一方面,这个上下文在编译时需要答案:
class Foo {
int x[factorial(4)];
};
constexpr
函数只保证在编译时被评估,如果它们是从constexpr
上下文调用的;否则由编译器决定是否在编译时进行评估(假设这样的优化是可能的,同样,取决于上下文)。
答案 1 :(得分:3)
你必须在const表达式中使用它,如:
constexpr auto res = factorial(2);
否则计算可以在运行时完成。
答案 2 :(得分:1)
constexpr
既不必要也足以编译函数的时间评估。
这是不够的,即使除了参数显然也必须是常量表达式这一事实。即使这是真的,符合标准的编译器也不必在编译时对其进行评估。如果它在constexpr上下文中,则只需在编译时进行评估。例如,将计算结果分配给constexpr
变量,或将值用作数组大小,或者作为非类型模板参数。
另一点是,编译器完全能够在编译时评估事物,即使没有constexpr。关于这一点存在很多困惑,并且不清楚为什么。 constexpr
函数的编译时评估从根本上归结为不断传播,编译器一直在进行这种优化:https://godbolt.org/g/Sy214U。
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n-1);
}
int foo() { return factorial(5); }
在gcc 6.3上用O3(和14)产生:
foo():
mov eax, 120
ret
本质上,在通过将constexpr
函数分配给另一个constexpr变量来绝对强制编译时评估的特定情况之外,编译时评估更多地与优化器的质量相关而不是标准。 / p>