Boost logo

Boost :

From: Zach Laine (whatwasthataddress_at_[hidden])
Date: 2019-12-09 21:44:59


On Mon, Dec 9, 2019 at 12:55 PM Andrzej Krzemienski <akrzemi1_at_[hidden]>
wrote:

>
>
> pon., 9 gru 2019 o 17:32 Zach Laine <whatwasthataddress_at_[hidden]>
> napisał(a):
>
>>
>>
>>
>>> Same with the iterator in the flight map:
>>>
>>>
>>>> https://github.com/tzlaine/flat_map/blob/master/implementation/flat_map#L266
>>>>
>>>
>>> According to C++17 requirements this shouldn't have been a
>>> random_access_iterator.
>>>
>>> Also, std::ranges::sort() will not work with it. But this is not
>>> directly related to `iterator_interface`
>>>
>>
>> I don't know why you think that. ranges::sort() is designed to work with
>> std::random_access_iterator, which is designed explicitly to support proxy
>> iterators. Casey and Eric have assured me that this "just works". Do you
>> know of a reason why it does not? If so, you've spotted a defect, and we
>> should file an LWG issue immediately.
>>
>
> Not sure if it is a defect. An iterator that returns a proxy as
> ::reference can be a valid random_access_iterator. However,
> std::ranges::sort(), apart from a random_access_iterator requirement, has
> one more requirement: sortable<>: (http://eel.is/c++draft/sort) which
> boils down to indirectly_writable (
> http://eel.is/c++draft/iterator.concept.writable). This last concepts
> puts severe restrictions on proxy types. For instance you should be able to
> assign to them when they are const-qualified. So a type like std::tuple<>
> of references will not work. But you will be able to design a sufficiently
> bizarre proxy type that will work with std::ranges::sort(), So in a way it
> will work with *some* reference proxies.
>

Ok, I just realized this somehow drifted off-list. Re-adding the list...

This is the definition of indirectly_writable:

template<class Out, class T>
  concept indirectly_writable =
    requires(Out&& o, T&& t) {
      *o = std::forward<T>(t); // not required to be equality-preserving
      *std::forward<Out>(o) = std::forward<T>(t); // not required to
be equality-preserving
      const_cast<const iter_reference_t<Out>&&>(*o) =
        std::forward<T>(t); // not required to be equality-preserving
      const_cast<const iter_reference_t<Out>&&>(*std::forward<Out>(o)) =
        std::forward<T>(t); // not required to be equality-preserving

};

All you need to make this work is a reference type for which all those are
well-formed. If you pick std::tuple, it all just works. If you pick
std::pair, only the first two expressions in the requires expression work.
You can easily define UDTs for which this concept works too, of course.

Zach


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