Thorsten, Thanks for the reply. See comments inline.
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.
When you say "overhead", are you speaking of size or speed? Was this overhead demonstrated by some particular use case? Does this mean you may be also removing the "singular" flag at some point? Is there a supported way of constructing valid empty ranges? I can't see that there's a way to do 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.
I feel that by the same token, you could say that a default constructed std::vector<T> is a bad idea. I really like using Boost.Range but I think this new behaviour is a big shortcoming. I also never saw any mention of these breaking changes on boost.devel...
template<class Range> void foo(boost::optional<const Range &> r_) { if (r && !r_->empty()) {...} }
might be an idea?
IMHO, this is obfuscated. There is a difference between an empty range and a range which is optional. In line with the std containers, I would argue that a default constructed range should be empty. It also quickly becomes cumbersome if your functions have multiple input ranges, like mine. Another problem I can see is overloading - you are forcing a user defined conversion, which is not going to be a better match than foo(const Range &); Also, if I have a typedef boost::range<Iter> MyRange, from a library users' perspective, calling foo(MyRange()) seems more intuitive than foo(boost::optional<const MyRange &>()); Anyway, unless I have any chance of making you change your mind, there doesn't seem much point in continuing this conversation. In any case, I've enjoyed using your library. I found it so useful I've built four other libraries, which are mostly based on passing data around through Boost.Ranges. I just wish that all of my code wasn't broken now that I've upgraded. Tom