使用另一个数组的值初始化本地静态const数组

时间:2016-05-10 08:08:51

标签: c++ arrays static initialization

假设我想声明一个 local 静态常量数组,但我不知道它在编译时的初始化值,并且必须先计算它们。 例如,我有一个数组int p[100]。我写了一个循环来填充前100个素数。在计算完这些之后,我定义了一个static const int primes[100],它必须由p的值初始化。我怎么能这样做?

P.S。问题" 为什么我想声明一个本地静态const对象?"可能没有一个令人满意的答案,但我认为这不是这种情况。

P.S.S。我作为一个例子提到了素数。这不是重点。

P.S.S.S。让我们说p有1000000名成员。那么user2079303建议的解决方案肯定值得更多的支持。

4 个答案:

答案 0 :(得分:2)

可以在运行时初始化一个静态const数组,但有点乏味:

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], // ...
};

答案 1 :(得分:1)

为了回避你的问题,使用模板元编程在编译时计算素数实际上是完全可行的。以下代码显示了执行此操作的可能方法。 main函数创建实例化PrimeGen类型以生成1st 100 primes的编译时std :: array。抱歉代码有点难以阅读,因为这里有很多模板样板。基本上,大多数逻辑都发生在第一个PrimeGen专业化中,它使用Eratosthenes筛来生成素数,使用以下基本公式:

  1. 从N = 100开始(尚未生成所需数量),Next = 2,空的素数列表和一个空的过滤器列表

  2. 检查Next是否为素数(即,传递所有现有过滤器)。如果是这样,将它添加到素数列表中,减少N并添加一个新的过滤器,该过滤器将无法传递可被Next整除的任何数字。

  3. 使用上述修改后的参数以及Next递增到Next + 1
  4. 进行下一次PrimeGen专业化的尝试
  5. 当N = 0
  6. 时终止

    显然,当编译器计算素数时,这个程序的编译时间会相对较长。

        #include <iostream>
        #include <array>
    
        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;
        }
    

答案 2 :(得分:0)

最有效的解决方案是:

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 };

您现在甚至可以取消整个p计算。

答案 3 :(得分:0)

我刚刚在另一个问题中阅读了this great answer并将其弄清楚了。无需将局部变量声明为static const。似乎只有static足以使计算值保持在范围之外。