7

C++11 hasn't range-based-loop for ranged integral sequence.

for(auto e : {0..10} )  // wouldn't compile!!!

So I just decided simulate it.

template< class T , bool enable = std::is_integral<T>::value >
struct range_impl
{
    struct iterator
    {
        constexpr T operator * ()const noexcept { return value; }
        iterator& operator ++()noexcept { ++value; return *this; }

        friend
        constexpr bool operator != (const iterator & lhs, const iterator rhs ) noexcept
        {
            return lhs.value != rhs.value;
        }
        T value;
    };

    constexpr iterator begin()const noexcept { return { first }; }
    constexpr iterator end  ()const noexcept { return { last  }; } 

    T first;
    T last ;
}; 




template< class T >
range_impl<T>  range(T first , T last) noexcept
{
    return {first, last};
}

int main(){
     // print numbers in [ 0..10 ), i.e. 0 1 2 3 4 5 6 7 8 9
     for(auto e : range(0,10) ) std::cout << e <<  ' ';
     std::cout << std::endl;
}

Q: How to generalize this method for ForwardIterators?

example:

template< class ForwardIterator, class T >
bool find(ForwardIterator first, ForwardIterator last, T const& value)
{
     for(auto e: range(first, last) ) if (e == v) return true;
     return false;
}
Khurshid Normuradov
  • 1,564
  • 1
  • 13
  • 20
  • 3
    That's not really *generalizing* it; integers are not iterators. You're basically making a new function with the same name. – Nicol Bolas Aug 28 '13 at 09:24

2 Answers2

6

Specialization

template< class Iterator>
struct range_impl<Iterator, false>
{
    range_impl(Iterator first, Iterator last)
    : first(first), last(last)
    {}

    constexpr Iterator begin()const noexcept { return { first }; }
    constexpr Iterator end  ()const noexcept { return { last  }; }

    Iterator first;
    Iterator last ;
};

Test:

int main(){
     for(auto e : range(0,10) ) std::cout << e <<  ' ';
     std::cout << std::endl;
     const char* a[] = { "Say", "hello", "to", "the", "world" };
     for(auto e : range(a, a + 5) ) std::cout << e <<  ' ';
     std::cout << std::endl;
}
  • You can also remove your integer based range implementation. Instead, create an integer iterator, and pass it to the iterator based range implementation (reduce code duplication!). Another thing my personal implementation of this does is it conditionally has `size` and `[]` defined if the iterator is random-access, and my integer iterator is random-access. – Yakk - Adam Nevraumont Aug 28 '13 at 16:01
1

You are trying to reimplement boost::iterator_range and boost::counting_iterator. Simply do this instead:

template< class T >
boost::iterator_range< boost::counting_iterator<T> > range( T const& tBegin, T const& tEnd ) {
    return boost::iterator_range< boost::counting_iterator<T> >( tBegin, tEnd );
}

There even exists a boost::counting_range already: http://www.boost.org/doc/libs/1_47_0/libs/range/doc/html/range/reference/ranges/counting_range.html

Sebastian
  • 4,802
  • 23
  • 48
  • for(auto e : temporaryObject{} ); -- for this case what do say standart, i.e. it guaranted that temporaryObject life time ended after loop or not? – Khurshid Normuradov Aug 28 '13 at 12:03
  • I took this paragraph out. I was partly mistaken. See here: http://stackoverflow.com/questions/9657708/c11-the-range-based-for-statement-range-init-lifetime – Sebastian Aug 28 '13 at 12:38
  • @KhurshidNormuradov yes, it dies. The semantics of ranged based for loops are clear (you can google sample implementations), and the lifetime of temporary objects created during it as well (the lifetime of a temporary bound to a reference is that reference's lifetime). – Yakk - Adam Nevraumont Aug 28 '13 at 16:04