You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编程初始化constexpr std::array成员?编译时生成前N个斐波那契数

编译时生成前N个斐波那契数的std::array结构体

你完全可以实现编译时可用的前N个斐波那契数数组!从C++14开始,std::array的constexpr支持已经足够完善,不需要退回到C数组或者Boost,只需要调整你的代码让初始化逻辑变成constexpr即可。


C++14及以上的解决方案

这是最简洁的实现方式,利用C++14放宽的constexpr函数规则(允许循环、条件分支),直接改造你原来的代码:

#include <array>
#include <iostream>

template <int N>
struct first_n_fibs {
    static_assert(N > 0, "N必须是正整数");
    
    // 改为constexpr函数,C++14允许在其中使用循环和条件判断
    static constexpr std::array<int, N> init_fibs() {
        std::array<int, N> result{};
        if (N >= 1) {
            result[0] = 1;
        }
        if (N >= 2) {
            result[1] = 1;
        }
        for (int i = 2; i < N; ++i) {
            result[i] = result[i-2] + result[i-1];
        }
        return result;
    }
    
    // 声明为constexpr静态成员,确保编译时初始化
    static constexpr std::array<int, N> vals = init_fibs();
};

// C++17之前需要在类外显式定义constexpr静态成员,C++17可省略
template <int N>
constexpr std::array<int, N> first_n_fibs<N>::vals;

int main() {
    // 这些访问都是编译时完成的,可以直接初始化constexpr变量
    constexpr auto fib2 = first_n_fibs<2>::vals.back();
    constexpr auto fib5 = first_n_fibs<5>::vals.back();
    constexpr auto fib6 = first_n_fibs<6>::vals.back();
    
    std::cout << fib2 << std::endl; // 输出1
    std::cout << fib5 << std::endl; // 输出5
    std::cout << fib6 << std::endl; // 输出8
}

关键改动说明:

  • 给init_fibs()加上constexpr关键字:C++14解除了constexpr函数只能有单一return语句的限制,你原来的循环和条件逻辑完全可以保留。
  • 将vals声明为constexpr static成员:编译器会在编译时就计算出数组的所有值,而非运行时延迟初始化。
  • 现在vals是真正的编译时常量,你可以用它初始化constexpr变量,甚至作为模板参数(只要元素类型符合要求)。

C++11的替代方案(旧标准兼容)

如果还在使用C++11,由于其constexpr函数不允许循环和条件分支,我们可以用模板元编程递归生成每个斐波那契数:

#include <array>
#include <iostream>

// 递归计算第n个斐波那契数的模板
template <int n>
struct fib_num {
    static constexpr int value = fib_num<n-1>::value + fib_num<n-2>::value;
};

// 边界条件特化
template <>
struct fib_num<0> {
    static constexpr int value = 1;
};

template <>
struct fib_num<1> {
    static constexpr int value = 1;
};

// 辅助模板:用整数序列展开生成数组
template <int N, int... Is>
constexpr std::array<int, N> make_fib_array(std::integer_sequence<int, Is...>) {
    return {{fib_num<Is>::value...}};
}

template <int N>
struct first_n_fibs {
    static_assert(N > 0, "N必须是正整数");
    
    static constexpr std::array<int, N> vals = make_fib_array<N>(std::make_integer_sequence<int, N>{});
};

template <int N>
constexpr std::array<int, N> first_n_fibs<N>::vals;

int main() {
    std::cout << first_n_fibs<2>::vals.back() << std::endl; // 1
    std::cout << first_n_fibs<5>::vals.back() << std::endl; //5
    std::cout << first_n_fibs<6>::vals.back() << std::endl; //8
}

说明:

这里通过模板递归计算每个斐波那契数,再利用std::integer_sequence(C14引入,C11可以自行实现简化版)展开参数包,生成std::array的初始化列表,同样能实现编译时初始化。


关于C数组的方案

如果一定要用C数组,思路和std::array完全一致,只需要把std::array<int, N>替换为int[N]即可,但std::array提供了更安全的容器接口(比如size()、at()),更推荐使用。

内容的提问来源于stack exchange,提问作者NoSenseEtAl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:49:12