From 333b6eb8c147fce1a9ddcd905ee3bb1a09b91e30 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 13 Nov 2019 17:10:47 -0800 Subject: [PATCH] P1878R1 Constraining Readable Types Instructions to change section names were ignored; the shorter section names are preferable, and the inclusion of 'iterator.' seems sufficient to indicate that we're talking about indirect reading and writing. Also fixes NB US 263, US 264, US 268 (C++20 CD), and LWG3279. --- source/algorithms.tex | 4 +- source/iterators.tex | 209 ++++++++++++++++++++++-------------------- 2 files changed, 114 insertions(+), 99 deletions(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index 0a265e924b..6df42bdf65 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -222,13 +222,13 @@ If \range{a}{b} denotes a range, the semantics of \tcode{b - a} in these cases are the same as those of \begin{codeblock} -iter_difference_t> n = 0; +iter_difference_t n = 0; for (auto tmp = a; tmp != b; ++tmp) ++n; return n; \end{codeblock} and if \range{b}{a} denotes a range, the same as those of \begin{codeblock} -iter_difference_t> n = 0; +iter_difference_t n = 0; for (auto tmp = b; tmp != a; ++tmp) --n; return n; \end{codeblock} diff --git a/source/iterators.tex b/source/iterators.tex index d84e116f0f..8bad7ba9b2 100644 --- a/source/iterators.tex +++ b/source/iterators.tex @@ -50,8 +50,8 @@ template using iter_difference_t = @\seebelow@; - // \ref{readable.traits}, readable traits - template struct readable_traits; + // \ref{readable.traits}, indirectly readable traits + template struct indirectly_readable_traits; template using iter_value_t = @\seebelow@; @@ -59,7 +59,7 @@ template struct iterator_traits; template requires is_object_v struct iterator_traits; - template<@\placeholder{dereferenceable}@ T> + template<@\exposconcept{dereferenceable}@ T> using iter_reference_t = decltype(*declval()); namespace ranges { @@ -73,7 +73,7 @@ } } - template<@\placeholder{dereferenceable}@ T> + template<@\exposconcept{dereferenceable}@ T> requires requires(T& t) { { ranges::iter_move(t) } -> @\placeholder{can-reference}@; } @@ -81,17 +81,17 @@ = decltype(ranges::iter_move(declval())); // \ref{iterator.concepts}, iterator concepts - // \ref{iterator.concept.readable}, concept \libconcept{readable} + // \ref{iterator.concept.readable}, concept \libconcept{indirectly_readable} template - concept readable = @\seebelow@; + concept indirectly_readable = @\seebelow@; - template + template using iter_common_reference_t = common_reference_t, iter_value_t&>; - // \ref{iterator.concept.writable}, concept \libconcept{writable} + // \ref{iterator.concept.writable}, concept \libconcept{indirectly_writable} template - concept writable = @\seebelow@; + concept indirectly_writable = @\seebelow@; // \ref{iterator.concept.winc}, concept \libconcept{weakly_incrementable} template @@ -161,11 +161,11 @@ concept indirect_strict_weak_order = @\seebelow@; template - requires (readable && ...) && invocable...> + requires (indirectly_readable && ...) && invocable...> using indirect_result_t = invoke_result_t...>; // \ref{projected}, projected - template Proj> + template Proj> struct projected; template @@ -474,7 +474,7 @@ \term{value type} of the iterator. An output iterator \tcode{i} has a non-empty set of types that are -\defn{writable} to the iterator; +\libconcept{indirectly_writable} to the iterator; for each such type \tcode{T}, the expression \tcode{*i = o} is valid where \tcode{o} is a value of type \tcode{T}. For every iterator type @@ -715,34 +715,37 @@ \indexlibraryglobal{iter_difference_t}% \pnum +Let $R_\tcode{I}$ be \tcode{remove_cvref_t}. The type \tcode{iter_difference_t} denotes \begin{itemize} \item -\tcode{incrementable_traits::difference_type} -if \tcode{iterator_traits} names a specialization +\tcode{incrementable_traits<$R_\tcode{I}$>::difference_type} +if \tcode{iterator_traits<$R_\tcode{I}$>} names a specialization generated from the primary template, and \item -\tcode{iterator_traits::\brk{}difference_type} otherwise. +\tcode{iterator_traits<$R_\tcode{I}$>::difference_type} otherwise. \end{itemize} \pnum Users may specialize \tcode{incrementable_traits} on program-defined types. -\rSec3[readable.traits]{Readable traits} +\rSec3[readable.traits]{Indirectly readable traits} \pnum -To implement algorithms only in terms of readable types, it is often necessary -to determine the value type that corresponds to a particular readable type. +To implement algorithms only in terms of indirectly readable types, +it is often necessary +to determine the value type that corresponds to +a particular indirectly readable type. Accordingly, it is required that if \tcode{R} is the name of a type that -models the \libconcept{readable} concept\iref{iterator.concept.readable}, +models the \libconcept{indirectly_readable} concept\iref{iterator.concept.readable}, the type \begin{codeblock} iter_value_t \end{codeblock} -be defined as the readable type's value type. +be defined as the indirectly readable type's value type. -\indexlibraryglobal{readable_traits}% +\indexlibraryglobal{indirectly_readable_traits}% \begin{codeblock} template struct @\placeholder{cond-value-type}@ { }; // \expos template @@ -751,30 +754,30 @@ using value_type = remove_cv_t; }; -template struct readable_traits { }; +template struct indirectly_readable_traits { }; template -struct readable_traits +struct indirectly_readable_traits : @\placeholder{cond-value-type}@ { }; template requires is_array_v -struct readable_traits { +struct indirectly_readable_traits { using value_type = remove_cv_t>; }; template -struct readable_traits - : readable_traits { }; +struct indirectly_readable_traits + : indirectly_readable_traits { }; template requires requires { typename T::value_type; } -struct readable_traits +struct indirectly_readable_traits : @\placeholder{cond-value-type}@ { }; template requires requires { typename T::element_type; } -struct readable_traits +struct indirectly_readable_traits : @\placeholder{cond-value-type}@ { }; template using iter_value_t = @\seebelow@; @@ -782,33 +785,35 @@ \indexlibraryglobal{iter_value_t}% \pnum +Let $R_\tcode{I}$ be \tcode{remove_cvref_t}. The type \tcode{iter_value_t} denotes \begin{itemize} \item -\tcode{readable_traits::value_type} -if \tcode{iterator_traits} names a specialization +\tcode{indirectly_readable_traits<$R_\tcode{I}$>::value_type} +if \tcode{iterator_traits<$R_\tcode{I}$>} names a specialization generated from the primary template, and \item -\tcode{iterator_traits::value_type} otherwise. +\tcode{iterator_traits<$R_\tcode{I}$>::value_type} otherwise. \end{itemize} \pnum -Class template \tcode{readable_traits} may be specialized +Class template \tcode{indirectly_readable_traits} may be specialized on program-defined types. \pnum \begin{note} Some legacy output iterators define a nested type named \tcode{value_type} -that is an alias for \tcode{void}. These types are not \tcode{readable} +that is an alias for \tcode{void}. +These types are not \tcode{indirectly_readable} and have no associated value types. \end{note} \pnum \begin{note} -Smart pointers like \tcode{shared_ptr} are \tcode{readable} and +Smart pointers like \tcode{shared_ptr} are \tcode{indirectly_readable} and have an associated value type, but a smart pointer like \tcode{shared_ptr} -is not \tcode{readable} and has no associated value type. +is not \tcode{indirectly_readable} and has no associated value type. \end{note} \rSec3[iterator.traits]{Iterator traits} @@ -870,11 +875,11 @@ concept @\placeholder{cpp17-input-iterator}@ = @\placeholder{cpp17-iterator}@ && equality_comparable && requires(I i) { typename incrementable_traits::difference_type; - typename readable_traits::value_type; + typename indirectly_readable_traits::value_type; typename common_reference_t&&, - typename readable_traits::value_type&>; + typename indirectly_readable_traits::value_type&>; typename common_reference_t::value_type&>; + typename indirectly_readable_traits::value_type&>; requires signed_integral::difference_type>; }; @@ -882,7 +887,8 @@ concept @\placeholder{cpp17-forward-iterator}@ = @\placeholder{cpp17-input-iterator}@ && constructible_from && is_lvalue_reference_v> && - same_as>, typename readable_traits::value_type> && + same_as>, + typename indirectly_readable_traits::value_type> && requires(I i) { { i++ } -> convertible_to; { *i++ } -> same_as>; @@ -941,7 +947,7 @@ publicly accessible members: \begin{codeblock} using iterator_category = @\seebelow@; -using value_type = typename readable_traits::value_type; +using value_type = typename indirectly_readable_traits::value_type; using difference_type = typename incrementable_traits::difference_type; using pointer = @\seebelow@; using reference = @\seebelow@; @@ -1091,9 +1097,9 @@ Let \tcode{\placeholder{iter-exchange-move}} be the exposition-only function: \begin{itemdecl} template - constexpr iter_value_t> @\placeholdernc{iter-exchange-move}@(X&& x, Y&& y) - noexcept(noexcept(iter_value_t>(iter_move(x))) && - noexcept(*x = iter_move(y))); + constexpr iter_value_t @\placeholdernc{iter-exchange-move}@(X&& x, Y&& y) + noexcept(noexcept(iter_value_t(iter_move(x))) && + noexcept(*x = iter_move(y))); \end{itemdecl} \begin{itemdescr} @@ -1101,7 +1107,7 @@ \effects Equivalent to: \begin{codeblock} -iter_value_t> old_value(iter_move(x)); +iter_value_t old_value(iter_move(x)); *x = iter_move(y); return old_value; \end{codeblock} @@ -1123,7 +1129,7 @@ ill-formed with no diagnostic required. \item Otherwise, if the types of \tcode{E1} and \tcode{E2} each model -\tcode{readable}, and if the reference types of \tcode{E1} and \tcode{E2} +\tcode{indirectly_readable}, and if the reference types of \tcode{E1} and \tcode{E2} model \libconcept{swappable_with}\iref{concept.swappable}, then \tcode{ranges::swap(*E1, *E2)}. @@ -1190,43 +1196,51 @@ and \tcode{\placeholder{ITER_CONCEPT}(I)} denotes \tcode{random_access_iterator_tag}. \end{example} -\rSec3[iterator.concept.readable]{Concept \cname{readable}} +\rSec3[iterator.concept.readable]{Concept \cname{indirectly_readable}} \pnum -Types that are readable by applying \tcode{operator*} -model the \libconcept{readable} concept, including +Types that are indirectly readable by applying \tcode{operator*} +model the \libconcept{indirectly_readable} concept, including pointers, smart pointers, and iterators. \begin{codeblock} template - concept @\deflibconcept{readable}@ = - requires { + concept @\defexposconcept{indirectly-readable-impl}@ = + requires(const In in) { typename iter_value_t; typename iter_reference_t; typename iter_rvalue_reference_t; + { *in } -> same_as>; + { iter_move(in) } -> same_as>; } && common_reference_with&&, iter_value_t&> && common_reference_with&&, iter_rvalue_reference_t&&> && common_reference_with&&, const iter_value_t&>; \end{codeblock} +\begin{codeblock} +template + concept @\deflibconcept{indirectly_readable}@ = + @\placeholdernc{indirectly-readable-impl}@>; +\end{codeblock} + \pnum -Given a value \tcode{i} of type \tcode{I}, \tcode{I} models \libconcept{readable} +Given a value \tcode{i} of type \tcode{I}, \tcode{I} models \libconcept{indirectly_readable} only if the expression \tcode{*i} is equality-preserving. \begin{note} The expression \tcode{*i} is indirectly required to be valid via the -exposition-only \placeholder{dereferenceable} concept\iref{iterator.synopsis}. +exposition-only \exposconcept{dereferenceable} concept\iref{iterator.synopsis}. \end{note} -\rSec3[iterator.concept.writable]{Concept \cname{writable}} +\rSec3[iterator.concept.writable]{Concept \cname{indirectly_writable}} \pnum -The \libconcept{writable} concept specifies the requirements for writing a value -into an iterator's referenced object. +The \libconcept{indirectly_writable} concept specifies the requirements +for writing a value into an iterator's referenced object. \begin{codeblock} template - concept @\deflibconcept{writable}@ = + concept @\deflibconcept{indirectly_writable}@ = requires(Out&& o, T&& t) { *o = std::forward(t); // not required to be equality-preserving *std::forward(o) = std::forward(t); // not required to be equality-preserving @@ -1240,10 +1254,10 @@ \pnum Let \tcode{E} be an expression such that \tcode{decltype((E))} is \tcode{T}, and let \tcode{o} be a dereferenceable object of type \tcode{Out}. -\tcode{Out} and \tcode{T} model \tcode{\libconcept{writable}} only if +\tcode{Out} and \tcode{T} model \tcode{\libconcept{indirectly_writable}} only if \begin{itemize} \item If \tcode{Out} and \tcode{T} model - \tcode{readable \&\& same_as, decay_t{>}}, + \tcode{indirectly_readable \&\& same_as, decay_t{>}}, then \tcode{*o} after any above assignment is equal to the value of \tcode{E} before the assignment. \end{itemize} @@ -1258,16 +1272,16 @@ \pnum \begin{note} The only valid use of an \tcode{operator*} is on the left side of the assignment statement. -Assignment through the same value of the writable type happens only once. +Assignment through the same value of the indirectly writable type happens only once. \end{note} \pnum \begin{note} -\tcode{writable} has the awkward \tcode{const_cast} expressions to reject +\tcode{indirectly_writable} has the awkward \tcode{const_cast} expressions to reject iterators with prvalue non-proxy reference types that permit rvalue assignment but do not also permit \tcode{const} rvalue assignment. Consequently, an iterator type \tcode{I} that returns \tcode{std::string} -by value does not model \tcode{\libconcept{writable}}. +by value does not model \tcode{\libconcept{indirectly_writable}}. \end{note} \rSec3[iterator.concept.winc]{Concept \cname{weakly_incrementable}} @@ -1599,8 +1613,8 @@ \pnum The \libconcept{input_iterator} concept defines requirements for a type whose referenced values can be read (from the requirement for -\libconcept{readable}\iref{iterator.concept.readable}) and which can be both pre- and -post-incremented. +\libconcept{indirectly_readable}\iref{iterator.concept.readable}) +and which can be both pre- and post-incremented. \begin{note} Unlike the \oldconcept{InputIterator} requirements\iref{input.iterators}, the \libconcept{input_iterator} concept does not need @@ -1611,7 +1625,7 @@ template concept @\deflibconcept{input_iterator}@ = input_or_output_iterator && - readable && + indirectly_readable && requires { typename @\placeholdernc{ITER_CONCEPT}@(I); } && derived_from<@\placeholdernc{ITER_CONCEPT}@(I), input_iterator_tag>; \end{codeblock} @@ -1621,7 +1635,8 @@ \pnum The \libconcept{output_iterator} concept defines requirements for a type that can be used to write values (from the requirement for -\libconcept{writable}\iref{iterator.concept.writable}) and which can be both pre- and post-incremented. +\libconcept{indirectly_writable}\iref{iterator.concept.writable}) +and which can be both pre- and post-incremented. \begin{note} Output iterators are not required to model \libconcept{equality_comparable}. \end{note} @@ -1630,7 +1645,7 @@ template concept @\deflibconcept{output_iterator}@ = input_or_output_iterator && - writable && + indirectly_writable && requires(I i, T&& t) { *i++ = std::forward(t); // not required to be equality-preserving }; @@ -2302,7 +2317,7 @@ namespace std { template concept @\deflibconcept{indirectly_unary_invocable}@ = - readable && + indirectly_readable && copy_constructible && invocable&> && invocable> && @@ -2313,7 +2328,7 @@ template concept @\deflibconcept{indirectly_regular_unary_invocable}@ = - readable && + indirectly_readable && copy_constructible && regular_invocable&> && regular_invocable> && @@ -2324,7 +2339,7 @@ template concept @\deflibconcept{indirect_unary_predicate}@ = - readable && + indirectly_readable && copy_constructible && predicate&> && predicate> && @@ -2332,7 +2347,7 @@ template concept @\deflibconcept{indirect_binary_predicate}@ = - readable && readable && + indirectly_readable && indirectly_readable && copy_constructible && predicate&, iter_value_t&> && predicate&, iter_reference_t> && @@ -2342,7 +2357,7 @@ template concept @\deflibconcept{indirect_equivalence_relation}@ = - readable && readable && + indirectly_readable && indirectly_readable && copy_constructible && equivalence_relation&, iter_value_t&> && equivalence_relation&, iter_reference_t> && @@ -2352,7 +2367,7 @@ template concept @\deflibconcept{indirect_strict_weak_order}@ = - readable && readable && + indirectly_readable && indirectly_readable && copy_constructible && strict_weak_order&, iter_value_t&> && strict_weak_order&, iter_reference_t> && @@ -2367,15 +2382,15 @@ \pnum Class template \tcode{projected} is used to constrain algorithms that accept callable objects and projections\iref{defns.projection}. -It combines a \libconcept{readable} type \tcode{I} and -a callable object type \tcode{Proj} into a new \libconcept{readable} type +It combines a \libconcept{indirectly_readable} type \tcode{I} and +a callable object type \tcode{Proj} into a new \libconcept{indirectly_readable} type whose \tcode{reference} type is the result of applying \tcode{Proj} to the \tcode{iter_reference_t} of \tcode{I}. \indexlibraryglobal{projected}% \begin{codeblock} namespace std { - template Proj> + template Proj> struct projected { using value_type = remove_cvref_t>; indirect_result_t operator*() const; // \notdef @@ -2397,8 +2412,8 @@ to families of algorithms. These group together iterator requirements of algorithm families. There are three relational concepts that specify -how element values are transferred between \libconcept{readable} and -\libconcept{writable} types: +how element values are transferred between +\libconcept{indirectly_readable} and \libconcept{indirectly_writable} types: \libconcept{indirectly_movable}, \libconcept{indirectly_copyable}, and \libconcept{indirectly_swappable}. @@ -2420,27 +2435,27 @@ \pnum The \libconcept{indirectly_movable} concept specifies the relationship between -a \libconcept{readable} type and a \libconcept{writable} type between which -values may be moved. +a \libconcept{indirectly_readable} type and a \libconcept{indirectly_writable} type +between which values may be moved. \begin{codeblock} template concept @\deflibconcept{indirectly_movable}@ = - readable && - writable>; + indirectly_readable && + indirectly_writable>; \end{codeblock} \pnum The \libconcept{indirectly_movable_storable} concept augments \libconcept{indirectly_movable} with additional requirements enabling the transfer to be performed through an intermediate object of the -\libconcept{readable} type's value type. +\libconcept{indirectly_readable} type's value type. \begin{codeblock} template concept @\deflibconcept{indirectly_movable_storable}@ = indirectly_movable && - writable> && + indirectly_writable> && movable> && constructible_from, iter_rvalue_reference_t> && assignable_from&, iter_rvalue_reference_t>; @@ -2462,28 +2477,28 @@ \pnum The \libconcept{indirectly_copyable} concept specifies the relationship between -a \libconcept{readable} type and a \libconcept{writable} type between which -values may be copied. +a \libconcept{indirectly_readable} type and a \libconcept{indirectly_writable} type +between which values may be copied. \begin{codeblock} template concept @\deflibconcept{indirectly_copyable}@ = - readable && - writable>; + indirectly_readable && + indirectly_writable>; \end{codeblock} \pnum The \libconcept{indirectly_copyable_storable} concept augments \libconcept{indirectly_copyable} with additional requirements enabling the transfer to be performed through an intermediate object of the -\libconcept{readable} type's value type. It also requires the capability +\libconcept{indirectly_readable} type's value type. It also requires the capability to make copies of values. \begin{codeblock} template concept @\deflibconcept{indirectly_copyable_storable}@ = indirectly_copyable && - writable&> && + indirectly_writable&> && copyable> && constructible_from, iter_reference_t> && assignable_from&, iter_reference_t>; @@ -2505,13 +2520,13 @@ \pnum The \libconcept{indirectly_swappable} concept specifies a swappable relationship -between the values referenced by two \libconcept{readable} types. +between the values referenced by two \libconcept{indirectly_readable} types. \begin{codeblock} template concept @\deflibconcept{indirectly_swappable}@ = - readable && readable && - requires(I1& i1, I2& i2) { + indirectly_readable && indirectly_readable && + requires(const I1 i1, const I2 i2) { ranges::iter_swap(i1, i1); ranges::iter_swap(i2, i2); ranges::iter_swap(i1, i2); @@ -4707,7 +4722,7 @@ decltype(auto) operator*(); decltype(auto) operator*() const - requires @\placeholder{dereferenceable}@; + requires @\exposconcept{dereferenceable}@; decltype(auto) operator->() const requires @\seebelow@; @@ -4860,7 +4875,7 @@ \begin{itemdecl} decltype(auto) operator*(); decltype(auto) operator*() const - requires @\placeholder{dereferenceable}@; + requires @\exposconcept{dereferenceable}@; \end{itemdecl} \begin{itemdescr} @@ -4883,7 +4898,7 @@ \pnum The expression in the requires clause is equivalent to: \begin{codeblock} -readable && +indirectly_readable && (requires(const I& i) { i.operator->(); } || is_reference_v> || constructible_from, iter_reference_t>) @@ -5142,7 +5157,7 @@ constexpr iter_difference_t count() const noexcept; constexpr decltype(auto) operator*(); constexpr decltype(auto) operator*() const - requires @\placeholder{dereferenceable}@; + requires @\exposconcept{dereferenceable}@; constexpr counted_iterator& operator++(); decltype(auto) operator++(int); @@ -5301,7 +5316,7 @@ \begin{itemdecl} constexpr decltype(auto) operator*(); constexpr decltype(auto) operator*() const - requires @\placeholder{dereferenceable}@; + requires @\exposconcept{dereferenceable}@; \end{itemdecl} \begin{itemdescr}