甲常量表达式意味着可以在编译时(程序运行之前,即,在编译期间)被编译器计算的表达式.
常量表达式可用于初始化标记的变量constexpr(参考C++ 11概念).这样的变量为编译器提供了可以进行编译时评估的提示(并且可以节省宝贵的运行时间),例如
#include <iostream>
constexpr int factorial(int n) // Everything here is known at compile time
{
return n <= 1 ? 1 : (n * factorial(n - 1));
}
int main(void)
{
constexpr int f = factorial(4); // 4 is also known at compile time
std::cout << f << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果不提供常量表达式,编译器无法在编译时实际完成所有这些工作:
#include <iostream>
constexpr int factorial(int n) // Everything here is known at compile time
{
return n <= 1 ? 1 : (n * factorial(n - 1));
}
int main(void)
{
int i;
std::cin >> i;
const int f = factorial(i); // I really can't guess this at compile time..
// thus it can't be marked with constexpr
std::cout << f << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译时额外工作而不是运行时工作的好处是性能提升,因为编译后的程序可能能够使用预先计算的值,而不必每次都从头开始计算它们.常量表达式越昂贵,程序获得的收益就越大.
在编译时知道什么值?
我认为谈论常量表达更有意义.常量表达式具有在编译时已知的值.粗略地说,它可能只是一个文字,另一个变量的名称(其值在编译时也是已知的)或涉及在编译时已知值的子表达式的复杂表达式.
引用声明声明的变量的初始值设定项constexpr需要是常量表达式.特别是表达必须满足的要求是一个常量表达式; 这些都列在这里.
例子是
constexpr int i = 54;
constexpr float f = 684; // Compile-time conversion from int to float
constexpr int func( int i )
{
return i*47 % 23;
}
constexpr auto value = func(i * f); // Okay; constexpr function called
// with arguments that, when substituted inside,
// yield constant expressions
Run Code Online (Sandbox Code Playgroud)
有时在编译时实际知道一个值,但根据标准,表达式不是常量.那包括
int i = 43;
constexpr int j = reinterpret_cast<int>(i); // Shouldn't compile. (Does with GCC)
Run Code Online (Sandbox Code Playgroud)
有些情况下编译器可能会进行常量折叠 - 某些值可以在编译时计算但不一定是.
int i = 0;
for (int j = 1; j != 10; ++j)
i += j;
return i;
Run Code Online (Sandbox Code Playgroud)
只要行为保持不变,编译器就可以完全消除循环并i使用55(或简单地返回55和消除i)进行初始化.这被称为as -if规则.
这意味着不需要运行程序来计算常数。例如:
int num = 4;
Run Code Online (Sandbox Code Playgroud)
您需要这些值,以便编译器将变量放置在符号表中,程序可以在其中引用和使用它们。对于常量,编译器将常量符号化为无法更改的值。因此,如果您将常量声明为在运行时确定的内容,它将不起作用,因为如果常量在编译时未定义,它就会保持未定义状态。我希望这是有道理的。
| 归档时间: |
|
| 查看次数: |
1799 次 |
| 最近记录: |