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

### 3470. `convertible-to-non-slicing` seems to reject valid case

Section: 26.5.4 [range.subrange] Status: WP Submitter: S. B. Tam Opened: 2020-07-26 Last modified: 2021-10-14

Priority: 3

View all other issues in [range.subrange].

View all issues with WP status.

Discussion:

Consider

>     #include <ranges>

>     int main()
>     {
>       int a[3] = { 1, 2, 3 };
>       int* b[3] = { &a[2], &a[0], &a[1] };
>       auto c = std::ranges::subrange<const int*const*>(b);
>     }

The construction of `c` is ill-formed because `convertible-to-non-slicing<int**, const int*const*>` is `false`, although the conversion does not involve object slicing.

I think `subrange` should allow such qualification conversion, just like `unique_ptr<T[]>` already does.

(Given that this constraint is useful in more than one context, maybe it deserves a named type trait?)

[2020-08-21; Reflector prioritization]

Set priority to 3 after reflector discussions.

[2021-05-19 Tim adds wording]

The wording below, which has been implemented and tested on top of libstdc++, uses the same technique we use for `unique_ptr`, `shared_ptr`, and `span`. It seems especially appropriate to have feature parity between `subrange` and `span` in this respect.

[2021-06-23; Reflector poll]

Set status to Tentatively Ready after five votes in favour during reflector poll.

[2021-10-14 Approved at October 2021 virtual plenary. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4885.

1. Modify 26.5.4 [range.subrange] as indicated:

   >     namespace std::ranges {
   >       template<class From, class To>
   >         concept uses-nonqualification-pointer-conversion = // exposition only
   >           is_pointer_v<From> && is_pointer_v<To> &&
   >           !convertible_to<remove_pointer_t<From>(*)[], remove_pointer_t<To>(*)[]>;

   >       template<class From, class To>
   >         concept convertible-to-non-slicing = // exposition only
   >           convertible_to<From, To> &&
   >           !uses-nonqualification-pointer-conversion<decay_t<From>, decay_t<To>>;
   >           !(is_pointer_v<decay_t<From>> &&
   >           is_pointer_v<decay_t<To>> &&
   >           not-same-as<remove_pointer_t<decay_t<From>>, remove_pointer_t<decay_t<To>>>
   >           );
   >       […]
   >     }
   >     […]