C++11编译时生成符合递推规则的常量数组P的实现方法
解决方案
在C++11中,我们可以通过constexpr递归函数+编译时索引序列或者纯模板元编程两种方式实现编译时生成符合规则的数组P。以下是具体实现:
方法一:constexpr函数 + 手动实现索引序列
这种方法利用C11的constexpr递归函数计算每个位置的P值,结合手动实现的index_sequence(C14标准库特性,C++11需自行实现)来展开生成整个数组。
#include <array> #include <cstdint> template <uint16_t N1, uint16_t N2, uint16_t... Ns> class TClass { public: static constexpr std::size_t S = sizeof...(Ns) + 2; static constexpr std::array<uint32_t, S> N = {N1, N2, Ns...}; private: // 手动实现C++14的std::index_sequence,用于生成编译时索引 template<std::size_t... Is> struct index_sequence {}; template<std::size_t N, std::size_t... Is> struct make_index_sequence : make_index_sequence<N-1, N-1, Is...> {}; template<std::size_t... Is> struct make_index_sequence<0, Is...> : index_sequence<Is...> {}; // 编译时计算P[i]:P[0]=1,P[i] = N[i-1] * P[i-1] constexpr static uint32_t compute_p(std::size_t i) { return i == 0 ? 1 : N[i-1] * compute_p(i-1); } // 通过索引序列展开,生成完整的P数组 template<std::size_t... Is> constexpr static std::array<uint32_t, S> generate_p(index_sequence<Is...>) { return {{ compute_p(Is)... }}; } public: static constexpr std::array<uint32_t, S> P = generate_p(make_index_sequence<S>()); }; // C++11要求复杂类型的静态constexpr成员必须在类外定义 template <uint16_t N1, uint16_t N2, uint16_t... Ns> constexpr std::array<uint32_t, TClass<N1,N2,Ns...>::S> TClass<N1,N2,Ns...>::P; // 测试用例 #include <iostream> int main() { TClass<3,5,9> instance; std::cout << "N: "; for (auto val : instance.N) std::cout << val << " "; std::cout << "\nP: "; for (auto val : instance.P) std::cout << val << " "; // 输出:N: 3 5 9 P: 1 3 15 return 0; }
关键说明:
- index_sequence实现:模拟C++14的
std::index_sequence,生成0到S-1的编译时索引序列,用于逐个计算每个位置的P值。 - compute_p函数:递归计算
P[i],符合规则P[0]=1,P[i] = N[i-1] * P[i-1],C++11允许constexpr函数使用三元运算符实现递归逻辑。 - 类外定义P:C++11规定,复杂类型(如
std::array)的静态constexpr成员必须在类外部完成定义,避免链接错误。
方法二:纯模板元编程
如果不想使用constexpr函数,可以完全依赖模板递归展开来生成乘积序列,再截取所需长度的数组:
#include <array> #include <cstdint> // 辅助模板:递归生成完整乘积序列 template<uint32_t CurrentProd, uint16_t... RemainingNs> struct ProductGenerator; // 终止条件:无剩余元素时返回仅包含当前乘积的数组 template<uint32_t CurrentProd> struct ProductGenerator<CurrentProd> { static constexpr std::array<uint32_t, 1> value = {CurrentProd}; }; // 递归步骤:将当前乘积加入序列,用CurrentProd*第一个N值继续生成后续序列 template<uint32_t CurrentProd, uint16_t FirstN, uint16_t... RemainingNs> struct ProductGenerator<CurrentProd, FirstN, RemainingNs...> { private: using NextGenerator = ProductGenerator<CurrentProd * FirstN, RemainingNs...>; public: static constexpr std::array<uint32_t, 1 + NextGenerator::value.size()> value = { CurrentProd, NextGenerator::value[0]... }; }; // 辅助模板:截取数组前N个元素 template<std::size_t Take, typename ArrayType, std::size_t... Is> struct TakeFirstElements : TakeFirstElements<Take-1, ArrayType, Take-1, Is...> {}; template<typename ArrayType, std::size_t... Is> struct TakeFirstElements<0, ArrayType, Is...> { using ValueType = typename ArrayType::value_type; static constexpr std::array<ValueType, sizeof...(Is)> value = {ArrayType::value[Is]...}; }; template <uint16_t N1, uint16_t N2, uint16_t... Ns> class TClass { public: static constexpr std::size_t S = sizeof...(Ns) + 2; static constexpr std::array<uint32_t, S> N = {N1, N2, Ns...}; // 生成完整乘积序列(长度S+1),截取前S个元素得到P using FullProductSeq = ProductGenerator<1, N1, N2, Ns...>; using PGenerator = TakeFirstElements<S, FullProductSeq>; static constexpr std::array<uint32_t, S> P = PGenerator::value; }; // 类外定义静态成员 template <uint16_t N1, uint16_t N2, uint16_t... Ns> constexpr std::array<uint32_t, TClass<N1,N2,Ns...>::S> TClass<N1,N2,Ns...>::N; template <uint16_t N1, uint16_t N2, uint16_t... Ns> constexpr std::array<uint32_t, TClass<N1,N2,Ns...>::S> TClass<N1,N2,Ns...>::P; // 测试用例 #include <iostream> int main() { TClass<3,5,9> instance; std::cout << "N: "; for (auto val : instance.N) std::cout << val << " "; std::cout << "\nP: "; for (auto val : instance.P) std::cout << val << " "; return 0; }
关键说明:
- ProductGenerator:递归生成从1开始的乘积序列,例如输入
1,3,5,9会生成{1,3,15,135}。 - TakeFirstElements:截取乘积序列的前
S个元素,得到符合要求的P数组。
内容的提问来源于stack exchange,提问作者bko
相关产品推荐
相关产品推荐

