Boost logo

Boost :

From: MaximYanchenko (maximyanchenko_at_[hidden])
Date: 2008-07-10 06:56:41


Hello,

I found that the input/output and comparison functions for iterator_range are
inside the header boost/range/iterator_range.hpp.

Actually, this causes problems, as I can't provide custom printing and custom
comparison: I have my own container printing engine and it worked perfectly well
with all standard containers, but failed to compile with iterator_range due to
operator<< ambiguity.
(Of course, I can just disable instantiation of my printing stuff for
iterator_range, but this is definitely not what I want to have.)
And, I have no such problems with, say, boost::tuple, as it has separate headers
for printing and comparison:
#include "boost/tuple/tuple_comparison.hpp"
#include "boost/tuple/tuple_io.hpp"

There are also other boost libraries that provide a separate "XXX_io.hpp" header.

So my proposal is:
1. Move operator<< to a separate header "boost/range/iterator_range_io.hpp"
2. Move comparison operators to a separate header
"boost/range/iterator_range_comparison.hpp"

This will also serve for boost unification, which is the Right Thing that
greatly simplifies usage of any library collection.

However, two problems arise here:
1. Backward compatibility. Current programs expect that everything is
automatically included. I see two solutions:
  - Include "boost/range/iterator_range_io.hpp" and
"boost/range/iterator_range_comparison.hpp" into
"boost/range/iterator_range.hpp" under a define like
BOOST_RANGE_1_34_COMPATIBILITY_MODE. This will give the same layout as we have
in Boost.Tuple, but I don't want to introduce extra macros if they can be easily
avioded.
  - Make one extra header "boost/range/iterator_range_core.hpp", and have
"boost/range/iterator_range.hpp" just including everything. This will the
hierarchical layout similar to other libraries like Boost.Spirit. In this case,
maybe it worth moving all three new headers to a subdirectory.

2. Again, backward compatibility, but from another point of view.
Boost.Range has the unspecified_bool_type() conversion operator.
I personally don't see a strong need in it, as it's just a negation of empty().
Also, no standard containers (which are ranges) offer this kind of conversion.
So I don't expect wide use of it, and maybe it's worth removing it from the
class at all and leave empty() only.

Anyway, for now it's here, so if you move operator<< away, iterator_range will
continue to be printed, but now, due to this conversion, it will be just "0" or
"1", depending on the range emptiness.
This is the problem not only for Boost.Range, but also for other types that
offer this kind of conversion and separate printing, for example, consider this
simple program with Boost.Optional:

#include <boost/optional/optional.hpp>
boost::optional<char> o('o');

#include <iostream>

void without_io()
{
  std::cout << "without_io: " << o << '\n';
}

#include <boost/optional/optional_io.hpp>

void with_io()
{
  std::cout << "with_io: " << o << '\n';
}

int main()
{
  without_io();
  with_io();
}

So, whether we change Boost.Range header leayout or not, this
unspecified_bool_type() problem should be solved anyway, for several boost
classes. I discussed this with Alex Nasonov, and he proposed a patch for
boost::optional:

https://svn.boost.org/trac/boost/ticket/2103

But this is not the only use of unspecified_bool_type, so most probably we will
need a common solution.

Thanks,
Maxim

P.S. Please write personal e-mails to gmail.com.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk