2016-05-10 2 views
1

Предположим, что я хочу объявить локальный статический постоянный массив , но я не знаю его значений инициализатора во время компиляции, и их нужно сначала вычислить. Например,, у меня есть массив int p[100]. Я пишу цикл, чтобы заполнить его с помощью первых 100 простых чисел. После вычисления, я определяю static const int primes[100], который должен быть инициализирован значениями p. Как я могу это сделать?Инициализировать локальный массив статических констант со значениями другого массива

P.S. Вопрос «почему Я хочу объявить локальный статический объект const?» может не иметь удовлетворительного ответа, но я думаю, что это не так.

P.S.S. Я упомянул простые числа как пример. Дело не в этом.

P.S.S.S. Скажем, p имеет 1000000 членов. Тогда решение, предложенное пользователем2079303, безусловно, заслуживает большего внимания.

+1

@EddeAlmeida - это просто неправда. Константы могут быть инициализированы во время выполнения, просто не изменены. Рассмотрим константы, локальные для функции – Smeeheey

+0

Ok @Smeeheey.Я удалил глупый комментарий, который я сделал раньше. –

+0

Я должен был сказать, что константы инициализируются, когда они созданы и не могут быть изменены после этого момента. Таким образом, нельзя просто создать константу, чтобы дать ей значение позже. Это верно? –

ответ

2

Можно инициализировать статический константный массив во время выполнения, но немного утомительно:

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

Чтобы обойти Ваш вопрос, на самом деле вполне возможно, чтобы ваши простые числа вычисляются во время компиляции с помощью шаблона мета- программирование. В приведенном ниже коде показан возможный способ сделать это. Основная функция создает экземпляр типа PrimeGen для генерации массива std :: compile-time из 1-го 100 простых чисел. Извиняется за то, что код несколько трудно читать, поскольку здесь много шаблонов котельной. В основном большая часть логики происходит в первой специализации PrimeGen, которая использует решето Эратосфена для генерации простых чисел, используя следующую основную формулу:

  1. начать с N = 100 (требуемое числом еще генерировать), следующий = 2, пустым списком простых чисел и пустым списком фильтров

  2. Проверьте, является ли Next простым (то есть передает все существующие фильтры). Если это так, добавьте его в список простых чисел, уменьшите N и добавьте новый фильтр, который не сможет передать любое число, делящееся на Next.

  3. Recurse к следующей специализации PrimeGen с выше измененными параметрами, а также с Далее увеличивается до Следующий + 1
  4. Terminate при 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; 
    } 
+0

Хотя я заявлял о грубости в качестве примера, и это было не так, но ваше решение кажется каким-то законным. +1 –

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 расчета в настоящее время.

+1

Вы шутите. правильно? –

+0

Нет. Зачем тратить время на расчет, когда результаты уже известны? –

0

Я только что прочитал this great answer другому вопросу в SO и понял это. Нет необходимости объявлять локальную переменную как static const. Кажется, что только static было бы достаточно, чтобы вычисленные значения не были сохранены вне области видимости.

+0

Это звучит не так. –

+0

Почему? @LightnessRacesinOrbit –

+0

Здесь не хватает подробностей, но из того, что вы нам сказали, это звучит как заблуждение. –

Смежные вопросы