题目
编写程序,比对 inline 与 constexpr 的机制边界。实现一个 constexpr 阶乘与斐波那契函数,验证其在传入编译期常量时能够在编译阶段直接折叠为纯立即数(用于初始化定长原生数组大小 int arr[fib(5)]);而在传入运行时变量时能够优雅降级为高效的普通运行时函数。
输入格式:无需外部输入。
输出格式:输出编译期折叠计算的数组尺寸验证与运行时降级调用的执行结果。
数据范围与约定:C++11/C++14 编译期求值与宏替换替代范式。
思路与算法
1. inline 与 constexpr 的本质区别inline 只是对编译器的优化建议,尝试消除函数调用跳转开销,并允许多个编译单元存在同名定义;而 constexpr 是语义强制的,向编译器保证只要参数是常量表达式,函数就能在编译期计算出结果。
2. 编译期与运行时双面性constexpr 函数具备双重特性:当上下文需要常量表达式(如模板非类型参数、数组长度)且实参是常量时在编译期执行;若实参是运行时输入,它自动退化为标准内联函数执行。
3. 编译期数组长度校验
通过 int arr[calcSize(6)]; 可绝对证明该函数求值发生在编译器解析抽象语法树阶段,否则数组定长声明会导致编译语法报错。
完整程序
#include <iostream>
// C++14 constexpr 允许使用局部变量与简单循环
constexpr unsigned long long constFactorial(int n) {
unsigned long long res = 1;
for (int i = 2; i <= n; ++i) {
res *= i;
}
return res;
}
int main() {
// 1. 编译期求值:用于原生定长数组维度初始化
constexpr int N = 5;
constexpr unsigned long long f5 = constFactorial(N); // 编译期彻底折叠为 120
// 使用编译期计算结果作为数组容量(如果不是编译期常量则无法通过编译)
int buffer[constFactorial(3)]; // constFactorial(3) = 6
std::cout << "静态数组 buffer 元素容量: " << sizeof(buffer) / sizeof(buffer[0]) << "\n";
std::cout << "编译期计算 constFactorial(5): " << f5 << "\n\n";
// 2. 运行时降级求值:传入动态变量
int runtimeInput = 6;
unsigned long long f6 = constFactorial(runtimeInput); // 降级为普通运行时内联函数
std::cout << "运行时动态传入 6 计算阶乘: " << f6 << "\n";
return 0;
}运行示例
输出:
静态数组 buffer 元素容量: 6
编译期计算 constFactorial(5): 120
运行时动态传入 6 计算阶乘: 720