This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

3407. Some problems with the wording changes of P1739R4

Section: [range.take.overview], 24.6.3 [range.iota] Status: New Submitter: Patrick Palka Opened: 2020-02-21 Last modified: 2020-03-29

Priority: 2

View all issues with New status.


Section 6.1 of P1739R4 changes the specification of views::take as follows:

-2- The name views::take denotes a range adaptor object (24.7.1 [range.adaptor.object]). Given subexpressions E and F, the expression views::take(E, F) is expression-equivalent to take_view{E, F}. Let E and F be expressions, let T be remove_cvref_t<decltype((E))>, and let D be range_difference_t<decltype((E))>. If decltype((F)) does not model convertible_to<D>, views::take(E, F) is ill-formed. Otherwise, the expression views::take(E, F) is expression-equivalent to:

  1. — if T is a specialization of ranges::empty_view ( [range.empty.view]), then ((void) F, decay-copy(E));

  2. — otherwise, if T models random_access_range and sized_range and is

    1. — a specialization of span (22.7.3 [views.span]) where T::extent == dynamic_extent,

    2. — a specialization of basic_string_view (21.4 [string.view]),

    3. — a specialization of ranges::iota_view ( [range.iota.view]), or

    4. — a specialization of ranges::subrange (24.5.3 [range.subrange]),

    then T{ranges::begin(E), ranges::begin(E) + min<D>(ranges::size(E), F)}, except that E is evaluated only once;

  3. — otherwise, ranges::take_view{E, F}.

Consider the case when T = subrange<counted_iterator<int>, default_sentinel_t>. Then according to the above wording, views::take(E, F) is expression-equivalent to

T{ranges::begin(E), ranges:begin(E) + min<D>(ranges::size(E), F)};   (*)

But this expression is ill-formed for the T we chose because subrange<counted_iterator<int>, default_sentinel_t> has no matching constructor that takes an iterator-iterator pair.

More generally the above issue applies anytime T is a specialization of subrange that does not model common_range. But a similar issue also exists when T is a specialization of iota_view whose value type differs from its bound type. In this case yet another issue arises: In order for the expression (*) to be well-formed when T is a specialization of iota_view, we need to be able to construct an iota_view out of an iterator-iterator pair, and for that it seems we need to add another constructor to iota_view.

[2020-02-24, Casey comments]

Furthermore, the pertinent subrange constructor is only available when subrange::StoreSize is false (i.e., when either the subrange specialization's third template argument is not subrange_kind::sized or its iterator and sentinel types I and S model sized_sentinel_for<S, I>).

[2020-03-16, Tomasz comments]

A similar problem occurs for the views::drop for the subrange<I, S, subrange_kind::sized>, that explicitly stores size (i.e. sized_sentinel_for<I, S> is false). In such case, the (iterator, sentinel) constructor that views::drop will be expression-equivalent is not available.

[2020-03-29 Issue Prioritization]

Priority to 2 after reflector discussion.

Proposed resolution: