Pythonish integer range in C++
Keeping a Count

You implemented range_iterator to keep a count which you use for equality comparisons. This works, but involves a really awkward formula for getting the count right. Instead, it would be simpler to just round end to be one past the last one, so that range(0, 11, 2) sets start to 0 and end to 12. This would make range_iterator only require two members, and operator!= to just compare the m_value's.

Wrong Type

range_iterator dereferences to int, but should be Int.

Usage

This is awkward:

for (auto i : range&lt;&gt;(start, end, step)) 
//                 ^^^


Rather than having it be up to the user to provide the correct type, you could instead take advantage of template deduction:

template &lt;typename Int&gt;
Range&lt;Int&gt; range(Int start, Int end, Int step) { ... }


You'll have to rename your class template to get this to work. Even better would be to make the function a friend of the class, and make the constructors private. 

Keep begin() and end() simple

Once we rewrite range() to be a function template that returns an object, you can move all of the logical checking into it:

template &lt;typename Int&gt;
Range&lt;Int&gt; range(Int start, Int end, Int step) {
    if (step == 0) throw ...;

    if (start &lt;= end) {
       if (step &lt; 0) {
           return {0,0,0};
       }
       return {start, (end + step - 1) / step * step};
    }
    else {
       // etc.
    }
}


This means that begin() just returns range_iterator{m_start, m_step} and end() just returns range_iterator{m_end, m_step}. 

Other Overloads

Python also allows for something like range(10), so that's just:

template &lt;class Int&gt;
Range&lt;Int&gt; range(Int end) {
    return {0, end, 1};
}


Iterator Interface

Even though it won't be fully utilized in the simple example of for (auto i : range(10)), you should prefer to provide a complete interface for range_iterator. You're missing operator== and postfix-increment. Prefix-increment (and postfix-increment) should return references to this. 

Additionally, you should inherit from std::iterator&lt;std::forward_iterator_tag, int, std::ptrdiff_t, int, int&gt; just in case somebody wants to use range() as a normal container somewhere else. 

For example, it'd be nice to support the following:

auto r = range(10);
std::vector&lt;int&gt; v(r.begin(), r.end());


which currently will fail to compile.