Issue 3470: convertible-to-non-slicing seems to reject valid case (original) (raw)


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

3470. _convertible-to-non-slicing_ seems to reject valid case

Section: 25.5.4 [range.subrange] Status: C++23 Submitter: S. B. Tam Opened: 2020-07-26 Last modified: 2023-11-22

Priority: 3

View all other issues in [range.subrange].

View all issues with C++23 status.

Discussion:

Consider

#include

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 betweensubrange 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 25.5.4 [range.subrange] as indicated:

    namespace std::ranges {
    template<class From, class To>
    concept uses-nonqualification-pointer-conversion = // exposition only
    is_pointer_v && is_pointer_v &&

 !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, decay_t>;
!(is_pointer_v<decay_t> &&
is_pointer_v<decay_t> &&
not-same-as<remove_pointer_t<decay_t>, remove_pointer_t<decay_t>>
);
[…]
}
[…]