Initialize a local static const array with values of another array
假设我想声明一个局部静态常量数组,但我不知道它的初始值设定项值在编译时,必须首先计算这些值。例如,我有一个数组
另外,"为什么我要声明一个本地静态常量对象?"可能没有令人满意的答案,但我认为情况并非如此。
P.S.S.我提到素数就是一个例子。这不是重点。
P.S.S.S.假设
可以在运行时初始化静态const数组,但有点乏味:
1 2 3 4 | int* init = get_run_time_array(); static const int primes[100] { init[0], init[1], init[1], init[2], init[3], init[4], init[5], // ... }; |
为了回避您的问题,实际上使用模板元编程在编译时计算素数是完全可行的。下面的代码显示了一种可能的方法。主函数创建实例化primegen类型以生成前100个prime的编译时std::数组。很抱歉,代码有点难阅读,因为这里有很多模板锅炉板。基本上,大多数逻辑发生在第一个素数专业化过程中,该过程使用埃拉托斯滕筛生成素数,使用以下基本公式:
从n=100(尚未生成的必需数字)开始,下一个=2,素数的空列表和过滤器的空列表
检查next是否为prime(即,通过所有现有过滤器)。如果是这样,将它添加到素数列表中,减少n并添加一个新的过滤器,它将无法通过任何可被next除尽的数字。
显然,只要编译器计算出素数,这个程序的编译时间就会相对较长。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | #include <iostream> #include template <size_t Mod> struct ModFilter { template<size_t N> static constexpr bool apply() { return N % Mod != 0; } }; template <size_t N, typename ... Filters> struct CheckFilters; template <size_t N> struct CheckFilters<N> { static const bool pass = true; }; template <size_t N, typename Filter, typename ... Filters> struct CheckFilters<N, Filter, Filters...> { static const bool pass = Filter::template apply<N>() && CheckFilters<N, Filters...>::pass; }; template<typename ... Filters> struct FilterPack{}; template<size_t ... Numbers> struct NumberList{}; template <size_t N, bool doAppend, typename Numbers> struct ConditionalAppend { typedef Numbers Output; }; template <size_t N, size_t ... Numbers> struct ConditionalAppend<N, true, NumberList<Numbers...>> { typedef NumberList<Numbers..., N> Output; }; template <size_t N, bool doAppend, typename Filters> struct ConditionalAppendFilter { typedef Filters Output; }; template <size_t N, typename ... Filters> struct ConditionalAppendFilter<N, true, FilterPack<Filters...>> { typedef FilterPack<Filters..., ModFilter<N>> Output; }; template<size_t N, size_t Next, typename Numbers, typename Filters> struct PrimeGen; template<size_t N, size_t Next, size_t ... Numbers, typename ... Filters> struct PrimeGen<N, Next, NumberList<Numbers...>, FilterPack<Filters...>> { static constexpr std::array<size_t, N + sizeof...(Numbers)> numbers = PrimeGen<CheckFilters<Next, Filters...>::pass ? N-1 : N, Next+1, typename ConditionalAppend<Next, CheckFilters<Next, Filters...>::pass, NumberList<Numbers...>>::Output, typename ConditionalAppendFilter<Next, CheckFilters<Next, Filters...>::pass, FilterPack<Filters...>>::Output> ::numbers; static const int size = N + sizeof...(Numbers); }; template<size_t Next, size_t ... Numbers, typename ... Filters> struct PrimeGen<0, Next, NumberList<Numbers...>, FilterPack<Filters...>> { static constexpr std::array<size_t, sizeof...(Numbers)> numbers = {Numbers...}; static const int size = sizeof...(Numbers); }; template<size_t N, size_t Next, size_t ... Numbers, typename ... Filters> constexpr std::array<size_t,N + sizeof...(Numbers)> PrimeGen<N, Next, NumberList<Numbers...>, FilterPack<Filters...>>::numbers; template<size_t Next, size_t ... Numbers, typename ... Filters> constexpr std::array<size_t,sizeof...(Numbers)> PrimeGen<0,Next,NumberList<Numbers...>,FilterPack<Filters...>>::numbers; int main() { using MyGen = PrimeGen<100, 2, NumberList<>, FilterPack<> >; for(int i=0; i<MyGen::size; ++i) std::cout << MyGen::numbers[i] << std::endl; return 0; } |
我刚刚读了这本书中对另一个问题的很好的答案,然后就明白了。不需要将局部变量声明为
最有效的解决方案是:
1 | static const int primes[100] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541 }; |
现在你甚至可以去掉你的整个