|
Boost Users : |
Subject: Re: [Boost-users] [range] const-only UDT works as std algos, but not with boost range.
From: Neil Groves (neil_at_[hidden])
Date: 2016-09-08 08:08:17
On 7 September 2016 at 22:18, John
<john2.718281828459045235360287_at_[hidden]> wrote:
> A class that exposes a const_iterator, but does not expose a mutable
> iterator, works with std:: algorithms and range-for() loop, but does not
> work with boost range.
This is true because it does not meet the requirements of the
Boost.Range Concepts (see
http://www.boost.org/doc/libs/1_61_0/libs/range/doc/html/range/concepts/single_pass_range.html).
To range requires a boost::range_iterator<T> and a
boost::range_iterator<const T>. There are several solutions. The
typical one is to simply add using iterator = const_iterator into the
type to model the range concept. However if one requires a
non-intrusive solution one can provide a specialization of
boost::range_iterator. This design decision for the concepts means
that there need not be const and mutable concepts for the ranges. It
also makes the selection of overrides work with typical models of the
Range Concepts such as Containers.
>
> // This works with std algorithms and range-for, but not with boost range.
> class C {
> public:
> typedef blah const_iterator;
> const_iterator begin() const;
> const_iterator end() const;
> };
> const C c;
> for (auto x : c) { } // OK
> std::for_each(std::begin(c), std::end(c), fn); // OK
> boost::for_each (c, fn); // ERROR: fails SinglePassRange concept (GCC-6.2)
>
>
> The workaround is to add a non-const iterator type that is the same as the
> const iterator, and to add two additional non-const begin/end methods.
>
This is more than necessary to fix the problem. You only need to add
using iterator = const_iterator; into class D. The additional begin()
and end() functions that return iterator are not required.
> class D {
> public:
> typedef blah const_iterator;
> const_iterator begin() const;
> const_iterator end() const;
>
> // kludge to make it work with boost.
> typedef const_iterator iterator;
> iterator begin();
> iterator end();
> };
>
> const D d;
> boost::for_each (d, fn); // OK
>
>
> Is there a simpler solution?
Yes, as described above all you need is one line so it models a Range
Concept. In other scenarios you might want to look at boost::sub_range
which will preserve const-ness from the wrapped type while providing
both const_iterator and iterator types
(http://www.boost.org/doc/libs/1_36_0/libs/range/doc/utility_class.html).
> _______________________________________________
> Boost-users mailing list
> Boost-users_at_[hidden]
> http://lists.boost.org/mailman/listinfo.cgi/boost-users
I hope this helps.
Regards,
Neil Groves
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net