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 in a manner that does no longer need similar adjustments.]
Modify 18.4.9 [concept.swappable] as indicated:
-2- The name
ranges::swapdenotes a customization point object (16.3.3.3.5 [customization.point.object]). The expressionranges::swap(E1, E2)for some subexpressionsE1andE2is expression-equivalent to an expressionSdetermined as follows:
(2.1) — […]
(2.2) — […]
(2.3) — Otherwise, if
E1andE2are lvalues of the same typeTthatmodelssatisfiesmove_constructible<T>andassignable_from<T&, T>,Sis an expression that exchanges the denoted values.Sis 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 subexpressionsE1andE2is expression-equivalent to:
(4.1) — […]
(4.2) — Otherwise, if the types of
E1andE2eachmodelsatisfyindirectly_readable, and if the reference types ofE1andE2modelsatisfyswappable_with(18.4.9 [concept.swappable]), thenranges::swap(*E1, *E2).(4.3) — Otherwise, if the types
T1andT2ofE1andE2modelsatisfyindirectly_movable_storable<T1, T2>andindirectly_movable_storable<T2, T1>, then(void)(*E1 = iter-exchange-move(E2, E1)), except thatE1is 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::prevto 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::advanceuses the+operator to move arandom_access_iteratorforwardnsteps in constant time. For an iterator type that does notmodelsatisfyrandom_access_iterator,ranges::advanceinstead performsnindividual 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
Imodelssatisfiesrandom_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
IandSmodelsatisfyassignable_from<I&, S>, equivalent toi = std::move(bound).(4.2) — Otherwise, if
SandImodelsatisfysized_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
SandImodelsatisfysized_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: IfSandImodelsatisfysized_sentinel_for<S, I>, returns(last - first); otherwise, returns the number of increments needed to get fromfirsttolast.template<range R> range_difference_t<R> ranges::distance(R&& r);-3- Effects: If
Rmodelssatisfiessized_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_conceptdenotes-2- The member typedef-name
(1.1) —
random_access_iterator_tagifIteratormodelssatisfiesrandom_access_iterator, and(1.2) —
bidirectional_iterator_tagotherwise.iterator_categorydenotes
(2.1) —
random_access_iterator_tagif the typeiterator_traits<Iterator>::iterator_categorymodelssatisfiesderived_from<random_access_iterator_tag>, and(2.2) —
iterator_traits<Iterator>::iterator_categoryotherwise.Modify 24.5.4.2 [move.iterator] as indicated:
-1- The member typedef-name
iterator_categorydenotes
(1.1) —
random_access_iterator_tagif the typeiterator_traits<Iterator>::iterator_categorymodelssatisfiesderived_from<random_access_iterator_tag>, and(1.2) —
iterator_traits<Iterator>::iterator_categoryotherwise.Modify 24.5.4.7 [move.iter.nav] as indicated:
constexpr auto operator++(int);-3- Effects:
Iteratormodelssatisfiesforward_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_traitsforcommon_iterator<I, S>are defined as follows.
(1.1) —
iterator_conceptdenotesforward_iterator_tagifImodelssatisfiesforward_iterator; otherwise it denotesinput_iterator_tag.(1.2) —
iterator_categorydenotesforward_iterator_tagifiterator_traits<I>::iterator_categorymodelssatisfiesderived_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: IfImodelssatisfiesforward_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::begindenotes a customization point object (16.3.3.3.5 [customization.point.object]). Given a subexpressionEand an lvaluetthat denotes the same object asE, ifEis 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 typeImodelssatisfiesinput_or_output_iterator.(1.3) — Otherwise,
decay-copy(begin(t))if it is a valid expression and its typeImodelssatisfiesinput_or_output_iteratorwith 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::enddenotes a customization point object (16.3.3.3.5 [customization.point.object]). Given a subexpressionEand an lvaluetthat denotes the same object asE, ifEis 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 typeSmodelssatisfiessentinel_for<decltype(ranges::begin(E))>.(1.3) — Otherwise,
decay-copy(end(t))if it is a valid expression and its typeSmodelssatisfiessentinel_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::rbegindenotes a customization point object (16.3.3.3.5 [customization.point.object]). Given a subexpressionEand an lvaluetthat denotes the same object asE, ifEis 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 typeImodelssatisfiesinput_or_output_iterator.(1.2) — Otherwise,
decay-copy(rbegin(t))if it is a valid expression and its typeImodelssatisfiesinput_or_output_iteratorwith 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 typeIwhichmodelssatisfiesbidirectional_iterator(24.3.4.12 [iterator.concept.bidir]).(1.4) — […]
Modify 25.3.7 [range.access.rend] as indicated:
-1- The name
ranges::renddenotes a customization point object (16.3.3.3.5 [customization.point.object]). Given a subexpressionEand an lvaluetthat denotes the same object asE, ifEis 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 typeSmodelssatisfiessentinel_for<decltype(ranges::rbegin(E))>.(1.2) — Otherwise,
decay-copy(rend(t))if it is a valid expression and its typeSmodelssatisfiessentinel_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 typeIwhichmodelssatisfiesbidirectional_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-likewhich 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
sizedenotes a customization point object (16.3.3.3.5 [customization.point.object]). The expressionranges::size(E)for some subexpressionEwith typeTis expression-equivalent to:
(1.1) — […]
(1.2) — Otherwise, if
disable_sized_range<remove_cv_t<T>>(25.4.4 [range.sized]) isfalse:
(1.2.1) —
decay-copy(E.size())if it is a valid expression andits typeIis 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 typeIis integer-likeis-integer-like<I>istruewith 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 typesIandSofranges::begin(E)andranges::end(E)(respectively)modelsatisfy bothsized_sentinel_for<S, I>(24.3.4.8 [iterator.concept.sizedsentinel]) andforward_iterator<I>. However,Eis evaluated only once.(1.4) — […]
Modify 25.3.13 [range.prim.empty] as indicated:
-1- The name
emptydenotes a customization point object (16.3.3.3.5 [customization.point.object]). The expressionranges::empty(E)for some subexpressionEis expression-equivalent to:
(1.1) — […]
(1.2) — […]
(1.3) — Otherwise,
EQ, whereEQisbool(ranges::begin(E) == ranges::end(E))except thatEis only evaluated once, ifEQis a valid expression and the type ofranges::begin(E)modelssatisfiesforward_iterator.(1.4) — […]
Modify 25.3.14 [range.prim.data] as indicated:
-1- The name
datadenotes a customization point object (16.3.3.3.5 [customization.point.object]). The expressionranges::data(E)for some subexpressionEis 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
[…]danglingis used together with the template aliasessafe_iterator_tandsafe_subrange_tto 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::findat #1 returnsranges::danglingsincef()is an rvaluevector; thevectorcould potentially be destroyed before a returned iterator is dereferenced. However, the calls at #2 and #3 both return iterators since the lvaluevecand specializations of subrangemodelsatisfyforwarding-range. — end example]Modify 25.6.4.3 [range.iota.iterator] as indicated:
-1-
iterator::iterator_categoryis defined as follows:
(1.1) — If
Wmodelssatisfiesadvanceable, theniterator_categoryisrandom_access_iterator_tag.(1.2) — Otherwise, if
Wmodelssatisfiesdecrementable, theniterator_categoryisbidirectional_iterator_tag.(1.3) — Otherwise, if
Wmodelssatisfiesincrementable, theniterator_categoryisforward_iterator_tag.(1.4) — Otherwise,
iterator_categoryisinput_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
Tmodelssatisfiesdefault_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::alldenotes 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 ofEmodelssatisfiesview.(2.2) — […]
(2.3) — […]
Modify 25.7.8.3 [range.filter.iterator] as indicated:
-2-
iterator::iterator_conceptis defined as follows:-3-
(2.1) — If
Vmodelssatisfiesbidirectional_range, theniterator_conceptdenotesbidirectional_iterator_tag.(2.2) — Otherwise, if
Vmodelssatisfiesforward_range, theniterator_conceptdenotesforward_iterator_tag.(2.3) — […]
iterator::iterator_categoryis defined as follows:
(3.1) — Let
Cdenote the typeiterator_traits<iterator_t<V>>::iterator_category.(3.2) — If
Cmodelssatisfiesderived_from<bidirectional_iterator_tag>, theniterator_categorydenotesbidirectional_iterator_tag.(3.3) — Otherwise, if
Cmodelssatisfiesderived_from<forward_iterator_tag>, theniterator_categorydenotesforward_iterator_tag.(3.4) — […]
Modify 25.7.9.3 [range.transform.iterator] as indicated:
-1-
iterator::iterator_conceptis defined as follows:-2- Let
(1.1) — If
Vmodelssatisfiesrandom_access_range, theniterator_conceptdenotesrandom_access_iterator_tag.(1.2) — Otherwise, if
Vmodelssatisfiesbidirectional_range, theniterator_conceptdenotesbidirectional_iterator_tag.(1.3) — Otherwise, if
Vmodelssatisfiesforward_range, theniterator_conceptdenotesforward_iterator_tag.(1.4) — […]
Cdenote the typeiterator_traits<iterator_t<Base>>::iterator_category. IfCmodelssatisfiesderived_from<contiguous_iterator_tag>, theniterator_categorydenotesrandom_access_iterator_tag; otherwise,iterator_categorydenotesC.Modify 25.7.14.3 [range.join.iterator] as indicated:
-1-
iterator::iterator_conceptis defined as follows:-2-
(1.1) — If
ref_is_glvalueistrueandBaseandrange_reference_t<Base>eachmodelsatisfybidirectional_range, theniterator_conceptdenotesbidirectional_iterator_tag.(1.2) — Otherwise, if
ref_is_glvalueistrueandBaseandrange_reference_t<Base>eachmodelsatisfyforward_range, theniterator_conceptdenotesforward_iterator_tag.(1.3) — […]
iterator::iterator_categoryis defined as follows:
(2.1) — Let […]
(2.2) — If
ref_is_glvalueistrueandOUTERCandINNERCeachmodelsatisfyderived_from<bidirectional_iterator_tag>,iterator_categorydenotesbidirectional_iterator_tag.(2.3) — Otherwise, if
ref_is_glvalueistrueandOUTERCandINNERCeachmodelsatisfyderived_from<forward_iterator_tag>,iterator_categorydenotesforward_iterator_tag.(2.4) — Otherwise, if
OUTERCandINNERCeachmodelsatisfyderived_from<input_iterator_tag>,iterator_categorydenotesinput_iterator_tag.(2.5) — […]
Modify [range.split.outer] as indicated:
[…] Parent* parent_ = nullptr; // exposition only iterator_t<Base> current_ = // exposition only, present only ifVmodelssatisfiesforward_rangeiterator_t<Base>(); […]-1- Many of the following specifications refer to the notional member
currentofouter_iterator.currentis equivalent tocurrent_ifVmodelssatisfiesforward_range, andparent_->current_otherwise.Modify [range.split.inner] as indicated:
-1- The typedef-name
iterator_categorydenotes
(1.1) —
forward_iterator_tagifiterator_traits<iterator_t<Base>>::iterator_categorymodelssatisfiesderived_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::counteddenotes a customization point object (16.3.3.3.5 [customization.point.object]). LetEandFbe expressions, and letTbedecay_t<decltype((E))>. Then the expressionviews::counted(E, F)is expression-equivalent to:
(2.1) — If
Tmodelssatisfiesinput_or_output_iteratoranddecltype((F))modelssatisfiesconvertible_to<iter_difference_t<T>>,
(2.1.1) —
subrange{E, E + static_cast<iter_difference_t<T>>(F)}ifTmodelssatisfiesrandom_access_iterator.(2.1.2) — […]
(2.2) — […]
Modify [range.common.adaptor] as indicated:
-1- The name
views::common denotesa 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_rangeandviews::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) —
S1andI1modelsatisfysized_sentinel_for<S1, I1>,(7.2) —
S2andI2modelsatisfysized_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, exactlyNapplications of the predicate and projection. At mostN/2swaps if the type offirstmeets the Cpp17BidirectionalIterator requirements for the overloads in namespacestdormodelssatisfiesbidirectional_iteratorfor the overloads in namespaceranges, and at mostNswaps 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.