On Wed, Nov 19, 2008 at 10:15 PM, Thorsten Ottosen <thorsten.ottosen@dezide.com> wrote:
Tomas Puverle skrev:

I just upgraded from Boost 1.33.1 to 1.37.0 and have found a breaking change in
Boost.Range.

Previously, iterator_range::empty() would do the following:

           bool empty() const
           {
               if( singular )
                   return true;
                               return m_Begin == m_End;
           }

and similarly for size().  In the new release, instead of the test, there is an
assertion, which is now breaking my code.

Why (and when?) was this change introduced?  This make Boost Range much in
generic code, such as

template<class Range>
void foo(const Range & r_)
{
 if (r_.empty()) {...}
}

The code is frequently called with containers and ranges and works beautifully.  However, a common pattern is to call the function with a default constructed
(empty range).  This now crashes.  The only way to test for validity AFAICS is
to call is_singular(), unfortunately, this breaks when the function is called
with containers.  
This, IMHO, was an unfortunate decision.  Any suggestions anyone?

The change has happened long ago. It was a design mistake to try to make a range of singular iterators valid since it adds overhead also for those that don't need it.

Your use-case is new to me, but seems quite ok. But making boost::iterator_range as a mixture of a range and boost.optional seems like a bad idea.

template<class Range>
void foo(boost::optional<const Range &> r_)
{
 if (r && !r_->empty()) {...}
}

might be an idea?


I too feel this change is a retrograde step. While I can see that there is some merit in
not making a singular range valid if we are starting from square-one, as a change to an
existing library I think this unacceptable.

Having a default constructed iterator range exhibit different behaviour from, say, a vector,
which is also a range seems wrong.

- Rob.