Improved indices trick We all know about the indices trick, right? Here's (hopefully) an improved version...

template &lt;::std::size_t...&gt; struct indices { };

namespace detail
{

template&lt;class A, class B&gt; struct catenate_indices;

template &lt;::std::size_t ...Is, ::std::size_t ...Js&gt;
struct catenate_indices&lt;indices&lt;Is...&gt;, indices&lt;Js...&gt; &gt;
{
  using indices_type = indices&lt;Is..., Js...&gt;;
};

template &lt;::std::size_t, ::std::size_t, typename = void&gt; struct expand_indices;

template &lt;::std::size_t A, ::std::size_t B&gt;
struct expand_indices&lt;A, B, typename ::std::enable_if&lt;A == B&gt;::type&gt;
{
  using indices_type = indices&lt;A&gt;;
};

template &lt;::std::size_t A, ::std::size_t B&gt;
struct expand_indices&lt;A, B, typename ::std::enable_if&lt;A != B&gt;::type&gt;
{
  static_assert(A &lt; B, "A &gt; B");
  using indices_type = typename catenate_indices&lt;
    typename expand_indices&lt;A, (A + B) / 2&gt;::indices_type,
    typename expand_indices&lt;(A + B) / 2 + 1, B&gt;::indices_type
  &gt;::indices_type;
};

}

template &lt;::std::size_t A&gt;
struct make_indices : detail::expand_indices&lt;0, A&gt;::indices_type
{
};

template &lt;::std::size_t A, ::std::size_t B&gt;
struct make_indices_range : detail::expand_indices&lt;A, B&gt;::indices_type
{
};


Usage:

#include &lt;iostream&gt;

#include "utility.hpp"

template &lt;::std::size_t ...Is&gt;
void show_indices(indices&lt;Is...&gt;)
{
  [](...){}((((::std::cout &lt;&lt; Is &lt;&lt; ::std::endl), 0))...);
}

int main()
{
  show_indices(make_indices_range&lt;3, 9&gt;());

  return 0;
}


Any suggestions?
You can get rid of the &lt;type_traits&gt; header by replacing your std::enable_if by a bool template specialization:

template &lt;::std::size_t, ::std::size_t, bool&gt;
struct expand_indices_impl;

template &lt;::std::size_t A, ::std::size_t B&gt;
struct expand_indices:
    expand_indices_impl&lt;A, B, A==B&gt;
{};

template &lt;::std::size_t A, ::std::size_t B&gt;
struct expand_indices_impl&lt;A, B, true&gt;
{
    using indices_type = indices&lt;A&gt;;
};

template &lt;::std::size_t A, ::std::size_t B&gt;
struct expand_indices_impl&lt;A, B, false&gt;
{
    static_assert(A &lt; B, "A &gt; B");
    using indices_type = typename catenate_indices&lt;
        typename expand_indices&lt;A, (A + B) / 2&gt;::indices_type,
        typename expand_indices&lt;(A + B) / 2 + 1, B&gt;::indices_type
    &gt;::indices_type;
};




Moreover, in C++ (and many other programming languages, see Python range for example), ranges tend to have the end-exclusive form [begin, end); therefore, make_indices_range&lt;3, 9&gt; should contain the indices from 3 to 8, and not from 3 to 9. It is easy to alter the behaviour:

template &lt;::std::size_t A&gt;
struct make_indices:
    detail::expand_indices&lt;0, A-1&gt;::indices_type
{};

template &lt;::std::size_t A, ::std::size_t B&gt;
struct make_indices_range:
    detail::expand_indices&lt;A, B-1&gt;::indices_type
{};


As proposed in the comments, make_indices_range also needs to provide an empty range when A == B:

template &lt;::std::size_t A&gt;
struct make_indices_range&lt;A, A&gt;:
    indices&lt;&gt;
{};