题目

编写程序,比对 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