如何编程初始化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
相关产品推荐
相关产品推荐

