【问题标题】:Initialize a local static const array with values of another array用另一个数组的值初始化一个本地静态常量数组
【发布时间】:2016-05-10 08:08:51
【问题描述】:

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

附: “为什么我要声明一个本地静态 const 对象?”的问题?可能没有令人满意的答案,但我认为这里不是这样。

附言我提到质数只是作为一个例子。这不是重点。

P.S.S.S.假设p 有 1000000 个成员。那么 user2079303 建议的解决方案肯定值得更多的支持。

【问题讨论】:

  • @EddeAlmeida - 这根本不是真的。常量可以在运行时初始化,只是不能改变。考虑函数的局部常量
  • 好的@Smeeheey。我删除了我之前发表的愚蠢评论。
  • 那么我应该说,常量在创建时就被初始化了,在那之后就不能再改变了。因此,不能只创建一个常量来稍后给它一个值。这是正确的吗?
  • 如果你真的需要一个不是真正 const 的静态 const 数组,我会使用 memcpyconst_cast 的组合。
  • 您能否提供更多详细信息? @KarstenKoop

标签: c++ arrays static initialization


【解决方案1】:

可以在运行时初始化一个静态常量数组,但是有点繁琐:

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

【讨论】:

    【解决方案2】:

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

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

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

    3. 使用上述修改后的参数以及 Next 递增到 Next+1,递归到 PrimeGen 的下一个特化
    4. 当 N=0 时终止

    显然这个程序的编译时间会比较长,因为编译器计算素数。

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

    【讨论】:

    • 虽然我以素数为例,但这不是重点,但您的解决方案似乎是合法的。 +1
    【解决方案3】:

    最有效的解决方案是:

    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 计算。

    【讨论】:

    • 不。既然已经知道结果,为什么还要浪费时间进行计算?
    【解决方案4】:

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

    【讨论】:

    • 为什么? @LightnessRacesinOrbit
    • 这里没有足够的细节可以说,但从你告诉我们的一点点来看,这听起来像是一种误解。
    • 在评论中,我说:例如,假设我计算p 的值,然后写someptr=&amp;p[0],其中someptr 是全局int*。如果我退出本地范围,计算值将被破坏。但是如果我首先将它们分配给一个静态常量数组,然后写入someptr=&amp;primes[0],它们将在本地范围之外保持不变。我希望这能澄清这个问题的原因,我真的看不出有什么误解。 @LightnessRacesinOrbit
    • 嗯,好的。在 this 答案中,您似乎建议 static 授予不变性。它没有。我想我不明白 const 与任何事情有什么关系。
    • 我同意。 const 这个词可能会引起一些误解。乍一看,我希望它们在本地范围内保持不变并且在本地范围外可访问。看来我们一般不能两者兼得。 @LightnessRacesinOrbit
    猜你喜欢
    • 1970-01-01
    • 2011-05-07
    • 1970-01-01
    • 2016-10-28
    • 2011-10-22
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多