关于c ++:使用另一个数组的值初始化本地静态const数组

Initialize a local static const array with values of another array

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

另外,"为什么我要声明一个本地静态常量对象?"可能没有令人满意的答案,但我认为情况并非如此。

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

P.S.S.S.假设p有1000000名成员。那么,用户2079303提出的解决方案肯定需要更多的赞成票。


可以在运行时初始化静态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的参数,递归到primegen的下一个专业化。
  • n=0时终止
  • 显然,只要编译器计算出素数,这个程序的编译时间就会相对较长。

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


    我刚刚读了这本书中对另一个问题的很好的答案,然后就明白了。不需要将局部变量声明为static const。似乎只有static才足以使计算值在范围之外保持完整。


    最有效的解决方案是:

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

    现在你甚至可以去掉你的整个p计算。