Compile-time sieve of Eratosthenes
I believe I can help with these things:


Obliterate macros
Obliterate raw arrays


Macros can be replaced with std::integer_sequence (C++14), and raw arrays can be replaced with std::array (C++11).

#include &lt;array&gt;
#include &lt;utility&gt;

template &lt;typename T, T... Is&gt;
constexpr auto gen_primes_helper(std::integer_sequence&lt;T, Is...&gt;) {
    return std::array&lt;T, sizeof...(Is)&gt;{{getPrime(Is)...}};
}

// T: integer type
// N: number of elements
// return: std::array&lt;T,N&gt;
template &lt;typename T, T N&gt;
constexpr auto gen_primes() {
    return gen_primes_helper(std::make_integer_sequence&lt;T,N&gt;());
}

constexpr auto primes = gen_primes&lt;int,1024&gt;();


However, we have a problem: Compilers currently implement std::make_integer_sequence in O(N) complexity.

GCC limits N to 900, unless you add the -ftemplate-depth= compiler option. See this bug.

Clang limits N to a pathetic 256, but also provides the same -ftemplate-depth= option.

To solve the problem, std::make_integer_sequence can be implemented in O(log(N)). I have done this as follows:

#include &lt;array&gt;
#include &lt;utility&gt;

namespace logseq {

// alias for std::integer_sequence, for brevity
template &lt;typename T, T... Is&gt;
using intseq_t = std::integer_sequence&lt;T, Is...&gt;;

template &lt;typename A, typename B&gt;
struct concat;

// A: intseq_t
// B: intseq_t
// return: typename intseq_t
//
// Example:
//   concat_t&lt; intseq_t&lt;int,0,1,2&gt;, intseq_t&lt;int,0,1,2,3&gt; &gt;
//     =&gt; intseq_t&lt;int,0,1,2,3,4,5,6&gt;
template &lt;typename A, typename B&gt;
using concat_t = typename concat&lt;A,B&gt;::type;

template &lt;typename T, T... As, T... Bs&gt;
struct concat&lt;intseq_t&lt;T, As...&gt;, intseq_t&lt;T, Bs...&gt;&gt; {
    using type = intseq_t&lt;T, As..., (sizeof...(As) + Bs)...&gt;;
};

template &lt;typename T, T N, typename = void&gt;
struct logseq;

// T: integer type
// N: number of elements
// return: typename std::make_integer_sequence&lt;T,N&gt;
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66059
template &lt;typename T, T N&gt;
using logseq_t = typename logseq&lt;T,N&gt;::type;

template &lt;typename T, T N, typename&gt;
struct logseq {
    using type = concat_t&lt;logseq_t&lt;T,N/2&gt;,logseq_t&lt;T,N-N/2&gt;&gt;;
};

template &lt;typename T, T N&gt;
struct logseq&lt;T,N,typename std::enable_if&lt;N==0&gt;::type&gt; {
    using type = intseq_t&lt;T&gt;;
};

template &lt;typename T, T N&gt;
struct logseq&lt;T,N,typename std::enable_if&lt;N==1&gt;::type&gt; {
    using type = intseq_t&lt;int,0&gt;;
};

} // namespace logseq


template &lt;typename T, T... Is&gt;
constexpr auto gen_primes_helper(std::integer_sequence&lt;T, Is...&gt;) {
    return std::array&lt;T, sizeof...(Is)&gt;{{getPrime(Is)...}};
}

// T: integer type
// N: number of elements
// return: std::array&lt;T,N&gt;
template &lt;typename T, T N&gt;
constexpr auto gen_primes() {
    using logseq::logseq_t;
    return gen_primes_helper(logseq_t&lt;T,N&gt;());
}

constexpr auto primes = gen_primes&lt;int,1024&gt;();


Namespace logseq provides a metafunction logseq_t that returns a typename std::integer_sequence&lt;T, 0, /* ... */, N-1&gt;. It is a drop-in replacement for std::make_integer_sequence, which returns the same type.

logseq_t allows for infinite (read: really freaking big) values of N.