A generic "manual" loop unroller I want to force my compiler (C++ or perhaps CUDA) to unroll certain loops that it would rather not unroll. So, I've written the following:

template &lt;size_t N&gt; struct unroller {
    template &lt;typename ForwardIterator, typename Function&gt;
    static void unroll(const Function&amp; f, ForwardIterator&amp; it) {
        unroll&lt;N/2, ForwardIterator, Function&gt;(f, it);
        ++it;
        unroll&lt;N-N/2, ForwardIterator, Function&gt;(f, it);
    }
};
template &lt;&gt; struct unroller&lt;0&gt; {
    template &lt;typename ForwardIterator, typename Function&gt;
    static void unroll(const Function&amp; f, ForwardIterator&amp; it) { }
};

template &lt;&gt; struct unroller&lt;1&gt; {
    template &lt;typename ForwardIterator, typename Function&gt;
    static void unroll(const Function&amp; f, ForwardIterator&amp; it) { f(it); }
};


I can also manually write in the instances at sizes 2,3,4 or so to perhaps reduce the amount of work the compiler needs to do. However, I was thinking maybe I should be doing something involving template packs and index lists to really cut down on the amount of instantiation. What do you think?

Sample usage:

#include &lt;iostream&gt;

// unroller code here

int main()
{
    constexpr unsigned unroll_factor = 3;
    constexpr unsigned total_iterations = 12;

    static_assert(total_iterations % unroll_factor == 0, 
        "Unroll factor must divide the number of iterations");

    auto f = [](int n) { std::cout &lt;&lt; n &lt;&lt; ' ' &lt;&lt; std::flush; };
    std::cout &lt;&lt; "no manual unrolling: ";
    for(int i = 0; i &lt; total_iterations; i++) { f(i); }
    std::cout &lt;&lt; std::endl &lt;&lt; "manual unrolling x " &lt;&lt; unroll_factor &lt;&lt; ": ";
    for(int i = 0; i &lt; total_iterations; i++) {
        unroller&lt;unroll_factor&gt;::unroll(f, i);
    }
    std::cout &lt;&lt; std::endl;
    return 0;
}
First, there are some errors that need to be fixed in order for your code to compile:


size_t needs to be std::size_t, or alternatively there needs to be an using std::size_t; declaration.
no matching function for call; you need to specify the template instantiation of the structure based on the "depth" as well as the function:

// WRONG:
unroll&lt;N/2, ForwardIterator, Function&gt;(f, it);
// FIXED:
unroller&lt;N/2&gt;::template unroll&lt;ForwardIterator, Function&gt;(f, it);



From a style perspective, I'd change the order of the template parameters to reflect the order in which the typenames appear in the parameter list (first the Function, then the ForwardIterator).

Then there's one thing that's a bit odd: Functions in the standard library which accept function objects (like std::sort, std::transform, ...) generally accept those function objects by value. This is done (probably) because that allows those functions objects to have mutable state. Your unroller accepts only references to constant function objects. That makes it (a bit) harder to have mutable state in the function object, like when you get one returned by some function:

auto make_that_function_object() {
    bool flag = true;
    return [flag](int n) mutable {
        if (flag) std::cout &lt;&lt; n &lt;&lt; ' ' &lt;&lt; std::flush;
        flag = !flag; };
}


The lambda returned by above function cannot be used with your unroller. To fix it (as a user of your unroller), you need another (non-mutable) lambda which references the original one:

auto original = make_that_function_object();
auto wrapper = [&amp;original](int n) { original(n); };


You could also solve this by accepting non-const references, though I'm not sure whether that's really better. (Accepting the function object by value does not solve the issue because then any changes to the internal state cannot be transferred "back up" the call chain or past "major" iterations of the top level loop.)