I am trying to extend the possibilities offered by std::integer_sequence
with a new class named integer_range
(which obiously creates a sequence of integers between two bounds). My implementation was based of my answer to this question that I tried to adapt to std::integer_sequence
:
namespace details
{
template<typename Int, Int C, Int P, Int... N>
struct increasing_integer_range:
increasing_integer_range<Int, C-1, P+1, N..., P>
{};
template<typename Int, Int C, Int P, Int... N>
struct decreasing_integer_range:
decreasing_integer_range<Int, C+1, P-1, N..., P>
{};
template<typename Int, Int P, Int... N>
struct increasing_integer_range<Int, 0, P, N...>:
std::integer_sequence<Int, N...>
{};
template<typename Int, Int P, Int... N>
struct decreasing_integer_range<Int, 0, P, N...>:
std::integer_sequence<Int, N...>
{};
}
template<typename Int, Int S, Int E, bool Increasing=(S<E)>
struct integer_range;
template<typename Int, Int S, Int E>
struct integer_range<Int, S, E, true>:
details::increasing_integer_range<Int, std::integral_constant<Int, E-S>, S>
{};
template<typename Int, Int S, Int E>
struct integer_range<Int, S, E, false>:
details::decreasing_integer_range<Int, std::integral_constant<Int, E-S>, S>
{};
template<std::size_t S, std::size_t E>
using index_range = integer_range<std::size_t, S, E>;
I thought that the change would be trivial (adding a typename
template parameter), but this actually introduces a problem with a dependant non-type parameter in the specialization for 0
. Here is the compiler error:
error: type `Int` of template argument `0` depends on a template parameter
The basic problem already has some solutions. However, since I use variadic templates, it becomes even harder to fix: this answer can't work because I it is not allowed to have a default template parameter after a variadic template. Therefore, I tried to implement the fix mentioned in the accepted answer but it seems that, as mentioned in the comments, my compiler (g++ 4.8.1) is unable to disambiguate and considers that the two following specialization are both equally specialized:
struct increasing_integer_range<Int, std::integral_constant<Int, C>, P, N...>: /* */
struct increasing_integer_range<Int, std::integral_constant<Int, 0>, P, N...>: /* */
Is there any other way to fix this problem? I am out of ideas.
I would simply reduce your
integer_range
to a single, non-recursive call tostd::integer_sequence
:Which I tested with:
getting the expected linker errors:
Live example (with own implementation of
integer_sequence
, just skip the first part)I'm just waiting for Yakk to suddenly appear out of nowhere and provide a non-hacky better solution ;) (I'm too tired to come up with something better..) but alas, this works for g++4.8.1:
The reason why I think this could be done better is that it seems the increasing and decreasing range implementations are redundant. But I might have to consider corner cases (overflow) before providing a unifying solution.
For example, you can easily make a shifted integer range by using
std::make_integer_range
plus partial specialization plus pack expansion. But this might overflow.A brief demonstration.