Created on 2019-09-10.00:00:00 last changed 45 months ago
Proposed resolution:
This wording is relative to N4830.
Modify [range.subrange] as indicated:
namespace std::ranges { template<class From, class To> concept convertible-to-non-slicing = // exposition only convertible_to<From, 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>>>); template<class T> concept pair-like = // exposition only […]template<class T, class U, class V> concept pair-like-convertible-to = // exposition only !range<T> && pair-like<remove_reference_t<T>> && requires(T&& t) { { get<0>(std::forward<T>(t)) } -> convertible_to<U>; { get<1>(std::forward<T>(t)) } -> convertible_to<V>; };template<class T, class U, class V> concept pair-like-convertible-from = // exposition only !range<T> && pair-like<T> && constructible_from<T, U, V> && convertible-to-non-slicing<U, tuple_element_t<0, T>> && convertible_to<V, tuple_element_t<1, T>>; […] […] template<input_or_output_iterator I, sentinel_for<I> S = I, subrange_kind K = sized_sentinel_for<S, I> ? subrange_kind::sized : subrange_kind::unsized> requires (K == subrange_kind::sized || !sized_sentinel_for<S, I>) class subrange : public view_interface<subrange<I, S, K>> { private: […] public: subrange() = default; constexpr subrange(convertible-to-non-slicing<I> auto i, S s) requires (!StoreSize); constexpr subrange(convertible-to-non-slicing<I> auto i, S s, make-unsigned-like-t(iter_difference_t<I>) n) requires (K == subrange_kind::sized); template<not-same-as<subrange> R> requires forwarding-range<R> &&convertible_toconvertible-to-non-slicing<iterator_t<R>, I> && convertible_to<sentinel_t<R>, S> constexpr subrange(R&& r) requires (!StoreSize || sized_range<R>); template<forwarding-range R> requiresconvertible_toconvertible-to-non-slicing<iterator_t<R>, I> && convertible_to<sentinel_t<R>, S> constexpr subrange(R&& r, make-unsigned-like-t(iter_difference_t<I>) n) requires (K == subrange_kind::sized) : subrange{ranges::begin(r), ranges::end(r), n} {}template<not-same-as<subrange> PairLike> requires pair-like-convertible-to<PairLike, I, S> constexpr subrange(PairLike&& r) requires (!StoreSize) : subrange{std::get<0>(std::forward<PairLike>(r)), std::get<1>(std::forward<PairLike>(r))} {} template<pair-like-convertible-to<I, S> PairLike> constexpr subrange(PairLike&& r, make-unsigned-like-t(iter_difference_t<I>) n) requires (K == subrange_kind::sized) : subrange{std::get<0>(std::forward<PairLike>(r)), std::get<1>(std::forward<PairLike>(r)), n} {}[…] }; template<input_or_output_iterator I, sentinel_for<I> S> subrange(I, S) -> subrange<I, S>; […] }
Modify [range.subrange.ctor] as indicated:
constexpr subrange(convertible-to-non-slicing<I> auto i, S s) requires (!StoreSize);-1- Expects: […]
[…]constexpr subrange(convertible-to-non-slicing<I> auto i, S s, make-unsigned-like-t(iter_difference_t<I>) n) requires (K == subrange_kind::sized);-2- Expects: […]
[…]template<not-same-as<subrange> R> requires forwarding-range<R> &&convertible_toconvertible-to-non-slicing<iterator_t<R>, I> && convertible_to<sentinel_t<R>, S> constexpr subrange(R&& r) requires (!StoreSize || sized_range<R>);-6- Effects: […]
[…]
[ 2020-02-10 Move to Immediate Monday afternoon in Prague ]
[ 2020-02-10; Prague ]
The group identified minor problems that have been fixed in the revised wording.
[ 2019-11 LEWG says OK; Status to Open. Friday PM discussion in Belfast. Casey to investigate and report back. ]
Previous resolution [SUPERSEDED]:
This wording is relative to N4830.
Modify [range.subrange] as indicated:
namespace std::ranges { template<class From, class To> concept convertible-to-non-slicing = // exposition only convertible_to<From, 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>>>); template<class T> concept pair-like = // exposition only […]template<class T, class U, class V> concept pair-like-convertible-to = // exposition only !range<T> && pair-like<remove_reference_t<T>> && requires(T&& t) { { get<0>(std::forward<T>(t)) } -> convertible_to<U>; { get<1>(std::forward<T>(t)) } -> convertible_to<V>; };template<class T, class U, class V> concept pair-like-convertible-from = // exposition only !range<T> && pair-like<T> && constructible_from<T, U, V> && convertible-to-non-slicing<U, tuple_element_t<0, T>> && convertible_to<V, tuple_element_t<1, T>>; […] […] template<input_or_output_iterator I, sentinel_for<I> S = I, subrange_kind K = sized_sentinel_for<S, I> ? subrange_kind::sized : subrange_kind::unsized> requires (K == subrange_kind::sized || !sized_sentinel_for<S, I>) class subrange : public view_interface<subrange<I, S, K>> { private: […] public: subrange() = default; constexpr subrange(convertible-to-non-slicing<I> auto i, S s) requires (!StoreSize); constexpr subrange(convertible-to-non-slicing<I> auto i, S s, make-unsigned-like-t(iter_difference_t<I>) n) requires (K == subrange_kind::sized); template<not-same-as<subrange> R> requires forwarding-range<R> &&convertible_toconvertible-to-non-slicing<iterator_t<R>, I> && convertible_to<sentinel_t<R>, S> constexpr subrange(R&& r) requires (!StoreSize || sized_range<R>); template<forwarding-range R> requires convertible_to<iterator_t<R>, I> && convertible_to<sentinel_t<R>, S> constexpr subrange(R&& r, make-unsigned-like-t(iter_difference_t<I>) n) requires (K == subrange_kind::sized) : subrange{ranges::begin(r), ranges::end(r), n} {}template<not-same-as<subrange> PairLike> requires pair-like-convertible-to<PairLike, I, S> constexpr subrange(PairLike&& r) requires (!StoreSize) : subrange{std::get<0>(std::forward<PairLike>(r)), std::get<1>(std::forward<PairLike>(r))} {} template<pair-like-convertible-to<I, S> PairLike> constexpr subrange(PairLike&& r, make-unsigned-like-t(iter_difference_t<I>) n) requires (K == subrange_kind::sized) : subrange{std::get<0>(std::forward<PairLike>(r)), std::get<1>(std::forward<PairLike>(r)), n} {}[…] }; template<input_or_output_iterator I, sentinel_for<I> S> subrange(I, S) -> subrange<I, S>; […] }Modify [range.subrange.ctor] as indicated:
constexpr subrange(convertible-to-non-slicing<I> auto i, S s) requires (!StoreSize);-1- Expects: […]
[…]constexpr subrange(convertible-to-non-slicing<I> auto i, S s, make-unsigned-like-t(iter_difference_t<I>) n) requires (K == subrange_kind::sized);-2- Expects: […]
[…]template<not-same-as<subrange> R> requires forwarding-range<R> &&convertible_toconvertible-to-non-slicing<iterator_t<R>, I> && convertible_to<sentinel_t<R>, S> constexpr subrange(R&& r) requires (!StoreSize || sized_range<R>);-6- Effects: […]
[…]
[ 2019-10; Marshall comments ]
This issue would resolve US-285.
[ 2019-10 Priority set to 1 and status to LEWG after reflector discussion ]
The following code leads to slicing and general badness:
struct Base {}; struct Derived : Base {}; subrange<Derived*> sd; subrange<Base*> sb = sd;
Traversal operations on iterators that are pointers do pointer arithmetic. If a Base* is actually pointing to a Derived*, then pointer arithmetic is invalid. subrange's constructors can easily flag this invalid code, and probably should.
The following PR incorporates the suggested fix to issue LWG 3281 I previously reported. Suggested priority: P1, since it will be hard to fix this after C++20 ships.History | |||
---|---|---|---|
Date | User | Action | Args |
2021-02-25 10:48:01 | admin | set | status: wp -> c++20 |
2020-02-24 16:02:59 | admin | set | status: immediate -> wp |
2020-02-10 19:48:51 | admin | set | messages: + msg11032 |
2020-02-10 19:48:51 | admin | set | status: open -> immediate |
2020-02-10 15:42:40 | admin | set | messages: + msg11013 |
2020-02-10 15:15:47 | admin | set | messages: + msg11011 |
2019-11-08 15:56:47 | admin | set | messages: + msg10808 |
2019-11-08 15:56:47 | admin | set | status: lewg -> open |
2019-10-07 02:21:30 | admin | set | messages: + msg10685 |
2019-10-07 02:21:30 | admin | set | status: new -> lewg |
2019-09-16 17:18:04 | admin | set | messages: + msg10635 |
2019-09-10 00:00:00 | admin | create |