This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.
Section: 18.4.9 [concept.swappable], 24.3.3.2 [iterator.cust.swap], 24.4.4.2 [range.iter.op.advance], 24.4.4.3 [range.iter.op.distance], 24.5.1.2 [reverse.iterator], 24.5.4.2 [move.iterator], 24.5.4.7 [move.iter.nav], 24.5.5.2 [common.iter.types], 24.5.5.5 [common.iter.nav], 25.3 [range.access], 25.6.4.3 [range.iota.iterator], 25.7 [range.adaptors], 26 [algorithms] Status: Resolved Submitter: Daniel Krügler Opened: 2019-11-23 Last modified: 2020-05-01
Priority: 2
View other active issues in [concept.swappable].
View all other issues in [concept.swappable].
View all issues with Resolved status.
Discussion:
The current working draft uses at several places within normative wording the term "models" instead of "satisfies" even though it is clear from the context that these are conditions to be tested by the implementation. Since "models" includes both syntactic requirements as well as semantic requirements, such wording would require (at least in general) heroic efforts for an implementation. Just to name a few examples for such misusage:
The specification of the customization objects in 18.4.9 [concept.swappable], 24.3.3.2 [iterator.cust.swap], 25.3 [range.access]
The algorithmic decision logic for the effects of the functions specified in 24.4.4.2 [range.iter.op.advance], 24.4.4.3 [range.iter.op.distance]
The correct way to fix these presumably unintended extra requirements is to use the term "satisfies" at the places where it is clear that an implementation has to test them.
Note: There exists similar misusage in regard to wording for types that "meet Cpp17XX requirements, but those are not meant to be covered as part of this issue. This additional wording problem should be handled by a separate issue.[2019-12-08 Issue Prioritization]
Priority to 2 after reflector discussion.
[2019-12-15; Daniel synchronizes wording with N4842]
Previous resolution [SUPERSEDED]:This wording is relative to N4842.
[Drafting note: The proposed wording does intentionally not touch the definition of
enable_view
, whose definition is radically changed by LWG 3326(i) in a manner that does no longer need similar adjustments.]
Modify 18.4.9 [concept.swappable] as indicated:
-2- The name
ranges::swap
denotes a customization point object (16.3.3.3.5 [customization.point.object]). The expressionranges::swap(E1, E2)
for some subexpressionsE1
andE2
is expression-equivalent to an expressionS
determined as follows:
(2.1) — […]
(2.2) — […]
(2.3) — Otherwise, if
E1
andE2
are lvalues of the same typeT
thatmodelssatisfiesmove_constructible<T>
andassignable_from<T&, T>
,S
is an expression that exchanges the denoted values.S
is a constant expression if […](2.4) — […]
Modify 24.3.3.2 [iterator.cust.swap] as indicated:
-4- The expression
ranges::iter_swap(E1, E2)
for some subexpressionsE1
andE2
is expression-equivalent to:
(4.1) — […]
(4.2) — Otherwise, if the types of
E1
andE2
eachmodelsatisfyindirectly_readable
, and if the reference types ofE1
andE2
modelsatisfyswappable_with
(18.4.9 [concept.swappable]), thenranges::swap(*E1, *E2)
.(4.3) — Otherwise, if the types
T1
andT2
ofE1
andE2
modelsatisfyindirectly_movable_storable<T1, T2>
andindirectly_movable_storable<T2, T1>
, then(void)(*E1 = iter-exchange-move(E2, E1))
, except thatE1
is evaluated only once.(4.4) — […]
Modify 24.4.4 [range.iter.ops] as indicated:
-1- The library includes the function templates
ranges::advance
,ranges::distance
,ranges::next
, andranges::prev
to manipulate iterators. These operations adapt to the set of operators provided by each iterator category to provide the most efficient implementation possible for a concrete iterator type. [Example:ranges::advance
uses the+
operator to move arandom_access_iterator
forwardn
steps in constant time. For an iterator type that does notmodelsatisfyrandom_access_iterator
,ranges::advance
instead performsn
individual increments with the++
operator. — end example]Modify 24.4.4.2 [range.iter.op.advance] as indicated:
template<input_or_output_iterator I> constexpr void ranges::advance(I& i, iter_difference_t<I> n);-1- Preconditions: […]
-2- Effects:
(2.1) — If
I
modelssatisfiesrandom_access_iterator
, equivalent toi += n
.(2.2) — […]
(2.3) — […]
template<input_or_output_iterator I, sentinel_for<I> S> constexpr void ranges::advance(I& i, S bound);-3- Preconditions: […]
-4- Effects:
(4.1) — If
I
andS
modelsatisfyassignable_from<I&, S>
, equivalent toi = std::move(bound)
.(4.2) — Otherwise, if
S
andI
modelsatisfysized_sentinel_for<S, I>
, equivalent toranges::advance(i, bound - i)
.(4.3) — […]
template<input_or_output_iterator I, sentinel_for<I> S> constexpr iter_difference_t<I> ranges::advance(I& i, iter_difference_t<I> n, S bound);-5- Preconditions: […]
-6- Effects:
(6.1) — If
S
andI
modelsatisfysized_sentinel_for<S, I>
: […](6.2) — […]
Modify 24.4.4.3 [range.iter.op.distance] as indicated:
template<input_or_output_iterator I, sentinel_for<I> S> constexpr iter_difference_t<I> ranges::distance(I first, S last);-1- Preconditions: […]
-2- Effects: IfS
andI
modelsatisfysized_sentinel_for<S, I>
, returns(last - first)
; otherwise, returns the number of increments needed to get fromfirst
tolast
.template<range R> range_difference_t<R> ranges::distance(R&& r);-3- Effects: If
R
modelssatisfiessized_range
, equivalent to:return static_cast<range_difference_t<R>>(ranges::size(r)); // 25.3.10 [range.prim.size]Otherwise, equivalent to:
return ranges::distance(ranges::begin(r), ranges::end(r)); // 25.3 [range.access]Modify 24.5.1.2 [reverse.iterator] as indicated:
-1- The member typedef-name
iterator_concept
denotes-2- The member typedef-name
(1.1) —
random_access_iterator_tag
ifIterator
modelssatisfiesrandom_access_iterator
, and(1.2) —
bidirectional_iterator_tag
otherwise.iterator_category
denotes
(2.1) —
random_access_iterator_tag
if the typeiterator_traits<Iterator>::iterator_category
modelssatisfiesderived_from<random_access_iterator_tag>
, and(2.2) —
iterator_traits<Iterator>::iterator_category
otherwise.Modify 24.5.4.2 [move.iterator] as indicated:
-1- The member typedef-name
iterator_category
denotes
(1.1) —
random_access_iterator_tag
if the typeiterator_traits<Iterator>::iterator_category
modelssatisfiesderived_from<random_access_iterator_tag>
, and(1.2) —
iterator_traits<Iterator>::iterator_category
otherwise.Modify 24.5.4.7 [move.iter.nav] as indicated:
constexpr auto operator++(int);-3- Effects:
Iterator
modelssatisfiesforward_iterator
, equivalent to:move_iterator tmp = *this; ++current; return tmp;Otherwise, equivalent to
++current
.Modify 24.5.5.2 [common.iter.types] as indicated:
-1- The nested typedef-names of the specialization of
iterator_traits
forcommon_iterator<I, S>
are defined as follows.
(1.1) —
iterator_concept
denotesforward_iterator_tag
ifI
modelssatisfiesforward_iterator
; otherwise it denotesinput_iterator_tag
.(1.2) —
iterator_category
denotesforward_iterator_tag
ifiterator_traits<I>::iterator_category
modelssatisfiesderived_from<forward_iterator_tag>
; otherwise it denotesinput_iterator_tag
.(1.3) — […]
Modify 24.5.5.5 [common.iter.nav] as indicated:
decltype(auto) operator++(int);-4- Preconditions: […]
-5- Effects: IfI
modelssatisfiesforward_iterator
, equivalent to:common_iterator tmp = *this; ++*this; return tmp;Otherwise, equivalent to
return get<I>(v_)++;
Modify 25.3.2 [range.access.begin] as indicated:
-1- The name
ranges::begin
denotes a customization point object (16.3.3.3.5 [customization.point.object]). Given a subexpressionE
and an lvaluet
that denotes the same object asE
, ifE
is an rvalue andenable_safe_range<remove_cvref_t<decltype((E))>>
isfalse
,ranges::begin(E)
is ill-formed. Otherwise,ranges::begin(E)
is expression-equivalent to:
(1.1) — […]
(1.2) — Otherwise,
decay-copy(t.begin())
if it is a valid expression and its typeI
modelssatisfiesinput_or_output_iterator
.(1.3) — Otherwise,
decay-copy(begin(t))
if it is a valid expression and its typeI
modelssatisfiesinput_or_output_iterator
with overload resolution performed in a context that includes the declarations:template<class T> void begin(T&&) = delete; template<class T> void begin(initializer_list<T>&&) = delete;and does not include a declaration of
ranges::begin
.(1.4) — […]
Modify 25.3.3 [range.access.end] as indicated:
-1- The name
ranges::end
denotes a customization point object (16.3.3.3.5 [customization.point.object]). Given a subexpressionE
and an lvaluet
that denotes the same object asE
, ifE
is an rvalue andenable_safe_range<remove_cvref_t<decltype((E))>>
isfalse
,ranges::end(E)
is ill-formed. Otherwise,ranges::end(E)
is expression-equivalent to:
(1.1) — […]
(1.2) — Otherwise,
decay-copy(t.end())
if it is a valid expression and its typeS
modelssatisfiessentinel_for<decltype(ranges::begin(E))>
.(1.3) — Otherwise,
decay-copy(end(t))
if it is a valid expression and its typeS
modelssatisfiessentinel_for<decltype(ranges::begin(E))>
with overload resolution performed in a context that includes the declarations:and does not include a declaration oftemplate<class T> void end(T&&) = delete; template<class T> void end(initializer_list<T>&&) = delete;ranges::end
.(1.4) — […]
Modify 25.3.6 [range.access.rbegin] as indicated:
-1- The name
ranges::rbegin
denotes a customization point object (16.3.3.3.5 [customization.point.object]). Given a subexpressionE
and an lvaluet
that denotes the same object asE
, ifE
is an rvalue andenable_safe_range<remove_cvref_t<decltype((E))>>
isfalse
,ranges::rbegin(E)
is ill-formed. Otherwise,ranges::rbegin(E)
is expression-equivalent to:
(1.1) —
decay-copy(t.rbegin())
if it is a valid expression and its typeI
modelssatisfiesinput_or_output_iterator
.(1.2) — Otherwise,
decay-copy(rbegin(t))
if it is a valid expression and its typeI
modelssatisfiesinput_or_output_iterator
with overload resolution performed in a context that includes the declaration:and does not include a declaration oftemplate<class T> void rbegin(T&&) = delete;ranges::rbegin
.(1.3) — Otherwise,
make_reverse_iterator(ranges::end(t))
if bothranges::begin(t)
andranges::end(t)
are valid expressions of the same typeI
whichmodelssatisfiesbidirectional_iterator
(24.3.4.12 [iterator.concept.bidir]).(1.4) — […]
Modify 25.3.7 [range.access.rend] as indicated:
-1- The name
ranges::rend
denotes a customization point object (16.3.3.3.5 [customization.point.object]). Given a subexpressionE
and an lvaluet
that denotes the same object asE
, ifE
is an rvalue andenable_safe_range<remove_cvref_t<decltype((E))>>
isfalse
,ranges::rend(E)
is ill-formed. Otherwise,ranges::rend(E)
is expression-equivalent to:
(1.1) —
decay-copy(t.rend())
if it is a valid expression and its typeS
modelssatisfiessentinel_for<decltype(ranges::rbegin(E))>
.(1.2) — Otherwise,
decay-copy(rend(t))
if it is a valid expression and its typeS
modelssatisfiessentinel_for<decltype(ranges::rbegin(E))>
with overload resolution performed in a context that includes the declaration:and does not include a declaration oftemplate<class T> void rend(T&&) = delete;ranges::rend
.(1.3) — Otherwise,
make_reverse_iterator(ranges::begin(t))
if bothranges::begin(t)
andranges::end(t)
are valid expressions of the same typeI
whichmodelssatisfiesbidirectional_iterator
(24.3.4.12 [iterator.concept.bidir]).(1.4) — […]
Modify 25.3.10 [range.prim.size] as indicated:
[Drafting note: The term "is integer-like" is very specifically defined to be related to semantic requirements as well, and the term "satisfy integer-like" seems to be undefined. Fortunately, 24.3.4.4 [iterator.concept.winc] also introduces the exposition-only variable template
is-integer-like
which we use as predicate below to describe the syntactic constraints of "integer-like" alone. This wording change regarding "is integer-like" is strictly speaking not required because of the "if and only if" definition provided in 24.3.4.4 [iterator.concept.winc] p12, but it has been made nonetheless to improve the consistency between discriminating compile-time tests from potentially semantic requirements]-1- The name
size
denotes a customization point object (16.3.3.3.5 [customization.point.object]). The expressionranges::size(E)
for some subexpressionE
with typeT
is expression-equivalent to:
(1.1) — […]
(1.2) — Otherwise, if
disable_sized_range<remove_cv_t<T>>
(25.4.3 [range.sized]) isfalse
:
(1.2.1) —
decay-copy(E.size())
if it is a valid expression andits typeI
is integer-likeis-integer-like<I>
istrue
(24.3.4.4 [iterator.concept.winc]).(1.2.2) — Otherwise,
decay-copy(size(E))
if it is a valid expression andits typeI
is integer-likeis-integer-like<I>
istrue
with overload resolution performed in a context that includes the declaration:and does not include a declaration oftemplate<class T> void size(T&&) = delete;ranges::size
.(1.3) — Otherwise,
make-unsigned-like(ranges::end(E) - ranges::begin(E))
(25.5.4 [range.subrange]) if it is a valid expression and the typesI
andS
ofranges::begin(E)
andranges::end(E)
(respectively)modelsatisfy bothsized_sentinel_for<S, I>
(24.3.4.8 [iterator.concept.sizedsentinel]) andforward_iterator<I>
. However,E
is evaluated only once.(1.4) — […]
Modify 25.3.12 [range.prim.empty] as indicated:
-1- The name
empty
denotes a customization point object (16.3.3.3.5 [customization.point.object]). The expressionranges::empty(E)
for some subexpressionE
is expression-equivalent to:
(1.1) — […]
(1.2) — […]
(1.3) — Otherwise,
EQ
, whereEQ
isbool(ranges::begin(E) == ranges::end(E))
except thatE
is only evaluated once, ifEQ
is a valid expression and the type ofranges::begin(E)
modelssatisfiesforward_iterator
.(1.4) — […]
Modify 25.3.13 [range.prim.data] as indicated:
-1- The name
data
denotes a customization point object (16.3.3.3.5 [customization.point.object]). The expressionranges::data(E)
for some subexpressionE
is expression-equivalent to:
(1.1) — […]
(1.2) — Otherwise, if
ranges::begin(E)
is a valid expression whose typemodelssatisfiescontiguous_iterator
,to_address(ranges::begin(E))
.(1.3) — […]
Modify 25.5.5 [range.dangling] as indicated:
-1- The tag type
[…]dangling
is used together with the template aliasessafe_iterator_t
andsafe_subrange_t
to indicate that an algorithm that typically returns an iterator into or subrange of a range argument does not return an iterator or subrange which could potentially reference a range whose lifetime has ended for a particular rvalue range argument which does notmodelsatisfyforwarding-range
(25.4.2 [range.range]).-2- [Example:
vector<int> f(); auto result1 = ranges::find(f(), 42); // #1 static_assert(same_as<decltype(result1), ranges::dangling>); auto vec = f(); auto result2 = ranges::find(vec, 42); // #2 static_assert(same_as<decltype(result2), vector<int>::iterator>); auto result3 = ranges::find(subrange{vec}, 42); // #3 static_assert(same_as<decltype(result3), vector<int>::iterator>);The call to
ranges::find
at #1 returnsranges::dangling
sincef()
is an rvaluevector
; thevector
could potentially be destroyed before a returned iterator is dereferenced. However, the calls at #2 and #3 both return iterators since the lvaluevec
and specializations of subrangemodelsatisfyforwarding-range
. — end example]Modify 25.6.4.3 [range.iota.iterator] as indicated:
-1-
iterator::iterator_category
is defined as follows:
(1.1) — If
W
modelssatisfiesadvanceable
, theniterator_category
israndom_access_iterator_tag
.(1.2) — Otherwise, if
W
modelssatisfiesdecrementable
, theniterator_category
isbidirectional_iterator_tag
.(1.3) — Otherwise, if
W
modelssatisfiesincrementable
, theniterator_category
isforward_iterator_tag
.(1.4) — Otherwise,
iterator_category
isinput_iterator_tag
.Modify [range.semi.wrap] as indicated:
-1- Many types in this subclause are specified in terms of an exposition-only class template
semiregular-box
.semiregular-box<T>
behaves exactly likeoptional<T>
with the following differences:
(1.1) — […]
(1.2) — If
T
modelssatisfiesdefault_constructible
, the default constructor ofsemiregular-box<T>
is equivalent to: […](1.3) — If
assignable_from<T&, const T&>
is notmodeledsatisfied, the copy assignment operator is equivalent to: […](1.4) — If
assignable_from<T&, T>
is notmodeledsatisfied, the move assignment operator is equivalent to: […]Modify 25.7.6 [range.all] as indicated:
-2- The name
views::all
denotes a range adaptor object (25.7.2 [range.adaptor.object]). For some subexpressionE
, the expressionviews::all(E)
is expression-equivalent to:
(2.1) —
decay-copy(E)
if the decayed type ofE
modelssatisfiesview
.(2.2) — […]
(2.3) — […]
Modify 25.7.8.3 [range.filter.iterator] as indicated:
-2-
iterator::iterator_concept
is defined as follows:-3-
(2.1) — If
V
modelssatisfiesbidirectional_range
, theniterator_concept
denotesbidirectional_iterator_tag
.(2.2) — Otherwise, if
V
modelssatisfiesforward_range
, theniterator_concept
denotesforward_iterator_tag
.(2.3) — […]
iterator::iterator_category
is defined as follows:
(3.1) — Let
C
denote the typeiterator_traits<iterator_t<V>>::iterator_category
.(3.2) — If
C
modelssatisfiesderived_from<bidirectional_iterator_tag>
, theniterator_category
denotesbidirectional_iterator_tag
.(3.3) — Otherwise, if
C
modelssatisfiesderived_from<forward_iterator_tag>
, theniterator_category
denotesforward_iterator_tag
.(3.4) — […]
Modify 25.7.9.3 [range.transform.iterator] as indicated:
-1-
iterator::iterator_concept
is defined as follows:-2- Let
(1.1) — If
V
modelssatisfiesrandom_access_range
, theniterator_concept
denotesrandom_access_iterator_tag
.(1.2) — Otherwise, if
V
modelssatisfiesbidirectional_range
, theniterator_concept
denotesbidirectional_iterator_tag
.(1.3) — Otherwise, if
V
modelssatisfiesforward_range
, theniterator_concept
denotesforward_iterator_tag
.(1.4) — […]
C
denote the typeiterator_traits<iterator_t<Base>>::iterator_category
. IfC
modelssatisfiesderived_from<contiguous_iterator_tag>
, theniterator_category
denotesrandom_access_iterator_tag
; otherwise,iterator_category
denotesC
.Modify 25.7.14.3 [range.join.iterator] as indicated:
-1-
iterator::iterator_concept
is defined as follows:-2-
(1.1) — If
ref_is_glvalue
istrue
andBase
andrange_reference_t<Base>
eachmodelsatisfybidirectional_range
, theniterator_concept
denotesbidirectional_iterator_tag
.(1.2) — Otherwise, if
ref_is_glvalue
istrue
andBase
andrange_reference_t<Base>
eachmodelsatisfyforward_range
, theniterator_concept
denotesforward_iterator_tag
.(1.3) — […]
iterator::iterator_category
is defined as follows:
(2.1) — Let […]
(2.2) — If
ref_is_glvalue
istrue
andOUTERC
andINNERC
eachmodelsatisfyderived_from<bidirectional_iterator_tag>
,iterator_category
denotesbidirectional_iterator_tag
.(2.3) — Otherwise, if
ref_is_glvalue
istrue
andOUTERC
andINNERC
eachmodelsatisfyderived_from<forward_iterator_tag>
,iterator_category
denotesforward_iterator_tag
.(2.4) — Otherwise, if
OUTERC
andINNERC
eachmodelsatisfyderived_from<input_iterator_tag>
,iterator_category
denotesinput_iterator_tag
.(2.5) — […]
Modify [range.split.outer] as indicated:
[…] Parent* parent_ = nullptr; // exposition only iterator_t<Base> current_ = // exposition only, present only ifV
modelssatisfiesforward_range
iterator_t<Base>(); […]-1- Many of the following specifications refer to the notional member
current
ofouter_iterator
.current
is equivalent tocurrent_
ifV
modelssatisfiesforward_range
, andparent_->current_
otherwise.Modify [range.split.inner] as indicated:
-1- The typedef-name
iterator_category
denotes
(1.1) —
forward_iterator_tag
ifiterator_traits<iterator_t<Base>>::iterator_category
modelssatisfiesderived_from<forward_iterator_tag>
;(1.2) — otherwise,
iterator_traits<iterator_t<Base>>::iterator_category
.Modify 25.7.19 [range.counted] as indicated:
-2- The name
views::counted
denotes a customization point object (16.3.3.3.5 [customization.point.object]). LetE
andF
be expressions, and letT
bedecay_t<decltype((E))>
. Then the expressionviews::counted(E, F)
is expression-equivalent to:
(2.1) — If
T
modelssatisfiesinput_or_output_iterator
anddecltype((F))
modelssatisfiesconvertible_to<iter_difference_t<T>>
,
(2.1.1) —
subrange{E, E + static_cast<iter_difference_t<T>>(F)}
ifT
modelssatisfiesrandom_access_iterator
.(2.1.2) — […]
(2.2) — […]
Modify [range.common.adaptor] as indicated:
-1- The name
views::common denotes
a range adaptor object (25.7.2 [range.adaptor.object]). For some subexpressionE
, the expressionviews::common(E)
is expression-equivalent to:
(1.1) —
views::all(E)
, ifdecltype((E))
modelssatisfiescommon_range
andviews::all(E)
is a well-formed expression.(1.2) — […]
Modify 26.6.13 [alg.equal] as indicated:
template<class InputIterator1, class InputIterator2> constexpr bool equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2); […] template<input_range R1, input_range R2, class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2> constexpr bool ranges::equal(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});[…]
-3- Complexity: If the types offirst1
,last1
,first2
, andlast2
:
(3.1) — meet the Cpp17RandomAccessIterator requirements (24.3.5.7 [random.access.iterators]) for the overloads in namespace
std
, or(3.2) — pairwise
modelsatisfysized_sentinel_for
(24.3.4.8 [iterator.concept.sizedsentinel]) for the overloads in namespaceranges
, andlast1 - first1 != last2 - first2
, then no applications of the corresponding predicate and each projection; otherwise,(3.3) — […]
(3.4) — […]
Modify 26.6.14 [alg.is.permutation] as indicated:
template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2, sentinel_for<I2> S2, class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2> constexpr bool ranges::is_permutation(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<forward_range R1, forward_range R2, class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2> constexpr bool ranges::is_permutation(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});[…]
-7- Complexity: No applications of the corresponding predicate and projections if:
(7.1) —
S1
andI1
modelsatisfysized_sentinel_for<S1, I1>
,(7.2) —
S2
andI2
modelsatisfysized_sentinel_for<S2, I2>
, and(7.3) — […]
Modify 26.8.5 [alg.partitions] as indicated:
template<class ForwardIterator, class Predicate> constexpr ForwardIterator partition(ForwardIterator first, ForwardIterator last, Predicate pred); […] template<forward_range R, class Proj = identity, indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred> requires permutable<iterator_t<R>> constexpr safe_subrange_t<R> ranges::partition(R&& r, Pred pred, Proj proj = {});[…]
-8- Complexity: LetN = last - first
:
(8.1) — For the overload with no
ExecutionPolicy
, exactlyN
applications of the predicate and projection. At mostN/2
swaps if the type offirst
meets the Cpp17BidirectionalIterator requirements for the overloads in namespacestd
ormodelssatisfiesbidirectional_iterator
for the overloads in namespaceranges
, and at mostN
swaps otherwise.(8.2) […]
[2020-02-10, Prague; Daniel comments]
I expect that P2101R0 (See D2101R0) is going to resolve this issue.
This proposal should also resolve the corresponding NB comments US-298 and US-300.[2020-05-01; reflector discussions]
Resolved by P2101R0 voted in in Prague.
Proposed resolution:
Resolved by P2101R0.