Prime number generator
How can I improve this code?


The code itself isn't particularly useful. You can print the primes up to N, but what if I wanted to sum all the primes up to N? In this model, you'd have to add a sum() member function to Prime&lt;i&gt; and again to Prime&lt;1&gt;. That doesn't make for a very reusable system. So let's go for something reusable, and in C++11 to boot.

Checking primality

Run isn't a particularly good name for a metafunction that determines if something is prime or not. Furthermore it doesn't even have to be a metafunction, it can be a constexpr function:

constexpr bool is_prime(std::size_t N)
{
    if (N &lt; 2) return false;

    for (std::size_t i=2; i*i &lt;= N; ++i) {
        if (N%i == 0) return false;
    }
    return true;
}


Check primality for lots of numbers

Your original example wanted all primes under 30. The standard metaprogramming mechanism for getting all numbers under 30 is:

using Nums = std::make_index_sequence&lt;31&gt;; // std::index_sequence&lt;0, 1, 2, ..., 30&gt;;


Although that gives us numbers and metaprogramming is all about types. Anything that isn't a type is usually a real nuisance to deal with, so let's write something to instead give us a list of types:

template &lt;typename T&gt;
struct type_is { using type = T; };

template &lt;typename...&gt;
struct typelist { };

namespace details {
    template &lt;std::size_t N, typename = std::make_index_sequence&lt;N&gt;&gt;
    struct make_type_index_sequence;

    template &lt;std::size_t N, std::size_t... Is&gt;
    struct make_type_index_sequence&lt;N, std::index_sequence&lt;Is...&gt;&gt; {
        using type = typelist&lt;std::integral_constant&lt;std::size_t, Is&gt;...&gt;;
    };
}

template &lt;std::size_t N&gt;
using make_type_index_sequence = typename details::make_type_index_sequence&lt;N&gt;::type;

// typelist&lt;size_t_&lt;0&gt;, size_t_&lt;1&gt;, ..., size_t_&lt;30&gt;&gt;, where size_t_&lt;N&gt; is integral_constant&lt;size_t, N&gt;
using Nums = make_type_index_sequence&lt;31&gt;; 


Ok, we have a typelist. Now we just need to filter it down based on a condition. To filter, we need to be able to concatenate:

template &lt;typename... Args&gt;
struct concat;

template &lt;typename... Args&gt;
using concat_t = typename concat&lt;Args...&gt;::type;

template &lt;typename... A1, typename... A2, typename... Args&gt;
struct concat&lt;typelist&lt;A1...&gt;, typelist&lt;A2...&gt;, Args...&gt; {
    using type = concat_t&lt;typelist&lt;A1..., A2...&gt;, Args...&gt;;
};

template &lt;typename TL&gt;
struct concat&lt;TL&gt; {
    using type = TL;
};


After which filter comes naturally:

template &lt;typename A, typename F&gt;
using filter_one = std::conditional_t&lt;F::template apply&lt;A&gt;::value,
                                      typelist&lt;A&gt;,
                                      typelist&lt;&gt;&gt;;

template &lt;typename TL, typename F&gt;
struct filter;

template &lt;typename... Args, typename F&gt;
struct filter&lt;typelist&lt;Args...&gt;, F&gt; {
    using type = concat_t&lt;filter_one&lt;Args, F&gt;...&gt;;
};

template &lt;typename TL, typename F&gt;
using filter_t = typename filter&lt;TL, F&gt;::type;


Metafunction classes

Something needs to be mentioned about this construction:

F::template apply&lt;A&gt;::value


Here F is a "metafunction class". That is, it's a type of the form:

struct MetafunctionClass {
    template &lt;typename... Args&gt;
    using apply = ???
};


Metaprogramming is all about convention. If everybody doesn't agree on convention, everybody's metaprograms may as well be written in different languages. The most core convention is that the "return" of a metafunction lives in a type named type. But a fairly common one is that when you need a "metafunctor", you pass something like this. The advantage of something like this is that it's always easy to create a type, but usually not so easy to create a template template (which would be the alternative).

Specifically here, we need:

struct IsPrime {
    template &lt;typename T&gt;
    using apply = std::integral_constant&lt;bool, is_prime(T::value)&gt;;
};


with which getting all the primes under 30 is:

template &lt;size_t N&gt;
using PrimesUnder = filter_t&lt;make_type_index_sequence&lt;N&gt;, IsPrime&gt;;


What can I do with this?

Well, anything really. Now that I made it easy to generate the primes, anything we may want to do with them is easy too. Printing them?

template &lt;typename... Ts, typename F&gt;
void for_each(typelist&lt;Ts...&gt;, F f) {
    using expander = int[];
    expander{0,
        (void(f(type_is&lt;Ts&gt;{})), 0)...
    };
}

for_each(PrimesUnder&lt;30&gt;{}, [](auto t) {
    std::cout &lt;&lt; "prime number: " &lt;&lt; decltype(t)::type::value &lt;&lt; std::endl;
});


Summing them?

template &lt;typename TL, typename F, typename Z&gt;
using foldl_t = ??? // exercise for the reader

struct Add {
    template &lt;typename T, typename U&gt;
    using apply = std::integral_constant&lt;decltype(T::value + U::value),
                      T::value + U::value
                      &gt;;
};

template &lt;size_t N&gt;
using SumOfPrimesUnder = foldl_t&lt;PrimesUnder&lt;N&gt;, Add, std::integral_constant&lt;int, 0&gt;&gt;;


Anything else you may need to do with your primes? You have the typelist - it's all in your hands.