diff --git a/source/utilities.tex b/source/utilities.tex index c9edf909d1..7758d0904f 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -6584,6 +6584,29 @@ // \ref{allocator.uses}, \tcode{uses_allocator} template struct uses_allocator; + // \ref{allocator.uses.trait}, \tcode{uses_allocator} + template + inline constexpr bool uses_allocator_v = uses_allocator::value; + + // \ref{allocator.uses.construction}, uses-allocator construction + template + auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) -> @\seebelow@; + template + auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, + Tuple1&& x, Tuple2&& y) -> @\seebelow@; + template + auto uses_allocator_construction_args(const Alloc& alloc) -> @\seebelow@; + template + auto uses_allocator_construction_args(const Alloc& alloc, U&& u, V&& v) -> @\seebelow@; + template + auto uses_allocator_construction_args(const Alloc& alloc, const pair& pr) -> @\seebelow@; + template + auto uses_allocator_construction_args(const Alloc& alloc, pair&& pr) -> @\seebelow@; + template + T make_obj_using_allocator(const Alloc& alloc, Args&&... args); + template + T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args); + // \ref{allocator.traits}, allocator traits template struct allocator_traits; @@ -6866,10 +6889,6 @@ // \ref{util.smartptr.atomic}, atomic smart pointers template struct atomic>; template struct atomic>; - - // \ref{allocator.uses.trait}, \tcode{uses_allocator} - template - inline constexpr bool uses_allocator_v = uses_allocator::value; } \end{codeblock} @@ -7274,31 +7293,237 @@ \rSec3[allocator.uses.construction]{Uses-allocator construction} \pnum -\defnx{Uses-allocator construction}{uses-allocator construction} with allocator \tcode{Alloc} refers to the -construction of an object \tcode{obj} of type \tcode{T}, using constructor arguments -\tcode{v1, v2, ..., vN} of types \tcode{V1, V2, ..., VN}, respectively, and an allocator -\tcode{alloc} of type \tcode{Alloc}, according to the following rules: +\defnx{Uses-allocator construction}{uses-allocator construction} +with allocator \tcode{alloc} and constructor arguments \tcode{args...} +refers to the construction of an object of type \tcode{T} +such that \tcode{alloc} is passed to the constructor of \tcode{T} +if \tcode{T} uses an allocator type compatible with \tcode{alloc}. +When applied to the construction of an object of type \tcode{T}, +it is equivalent to initializing it with the value of the expression +\tcode{make_obj_using_allocator(alloc, args...)}, described below. +\pnum +The following utility functions support +three conventions for passing \tcode{alloc} to a constructor: \begin{itemize} -\item if \tcode{uses_allocator_v} is \tcode{false} and -\tcode{is_constructible_v} is \tcode{true}, then \tcode{obj} is -initialized as \tcode{obj(v1, v2, ..., vN)}; - -\item otherwise, if \tcode{uses_allocator_v} is \tcode{true} and -\tcode{is_constructible_v} is -\tcode{true}, then \tcode{obj} is initialized as \tcode{obj(allocator_arg, alloc, v1, -v2, ..., vN)}; - -\item otherwise, if \tcode{uses_allocator_v} is \tcode{true} and -\tcode{is_constructible_v} is \tcode{true}, then -\tcode{obj} is initialized as \tcode{obj(v1, v2, ..., vN, alloc)}; - -\item otherwise, the request for uses-allocator construction is ill-formed. \begin{note} -An error will result if \tcode{uses_allocator_v} is \tcode{true} but the -specific constructor does not take an allocator. This definition prevents a silent -failure to pass the allocator to an element. \end{note} +\item + If \tcode{T} does not use an allocator compatible with \tcode{alloc}, + then \tcode{alloc} is ignored. +\item + Otherwise, if \tcode{T} has a constructor invocable as + \tcode{T(allocator_arg, alloc, args...)} (leading-allocator convention), + then uses-allocator construction chooses this constructor form. +\item + Otherwise, if \tcode{T} has a constructor invocable as + \tcode{T(args..., allocator)} (trailing-allocator convention), + then uses-allocator construction chooses this constructor form. \end{itemize} +\pnum +The \tcode{uses_allocator_construction_args} function template +takes an allocator and argument list and +produces (as a tuple) a new argument list matching one of the above conventions. +Additionally, overloads are provided +that treat specializations of \tcode{pair} +such that uses-allocator construction is applied individually +to the \tcode{first} and \tcode{second} data members. +The \tcode{make_obj_using_allocator} and +\tcode{uninitialized_construct_using_allocator} function templates +apply the modified constructor arguments +to construct an object of type \tcode{T} +as a return value or in-place, respectively. +\begin{note} +For \tcode{uses_allocator_construction_args} and +\tcode{make_obj_using_allocator}, type \tcode{T} +is not deduced and must therefore be specified explicitly by the caller. +\end{note} + +\indexlibrary{\idxcode{uses_allocator_construction_args}}% +\begin{itemdecl} +template + auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) -> @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is not a specialization of \tcode{pair}. + +\pnum +\returns +A \tcode{tuple} value determined as follows: +\begin{itemize} +\item + If \tcode{uses_allocator_v} is \tcode{false} and + \tcode{is_constructible_v} is \tcode{true}, + return \tcode{forward_as_tuple(std::forward(args)...)}. +\item + Otherwise, if \tcode{uses_allocator_v} is \tcode{true} and + \tcode{is_constructible_v} + is \tcode{true}, + return +\begin{codeblock} +tuple( + allocator_arg, alloc, std::forward(args)...) +\end{codeblock} +\item + Otherwise, if \tcode{uses_allocator_v} is \tcode{true} and + \tcode{is_constructible_v} is \tcode{true}, + return \tcode{forward_as_tuple(std::forward(args)..., alloc)}. +\item + Otherwise, the program is ill-formed. +\end{itemize} +\begin{note} +This definition prevents a silent failure +to pass the allocator to a constructor of a type for which +\tcode{uses_allocator_v} is \tcode{true}. +\end{note} +\end{itemdescr} + +\indexlibrary{\idxcode{uses_allocator_construction_args}}% +\begin{itemdecl} +template + auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, + Tuple1&& x, Tuple2&& y) -> @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a specialization of \tcode{pair}. + +\pnum +\effects +For \tcode{T} specified as \tcode{pair}, equivalent to: +\begin{codeblock} +return make_tuple( + piecewise_construct, + apply([&alloc](auto&&... args1) { + return uses_allocator_construction_args( + alloc, std::forward(args1)...); + }, std::forward(x)), + apply([&alloc](auto&&... args2) { + return uses_allocator_construction_args( + alloc, std::forward(args2)...); + }, std::forward(y))); +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{uses_allocator_construction_args}}% +\begin{itemdecl} +template + auto uses_allocator_construction_args(const Alloc& alloc) -> @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a specialization of \tcode{pair}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +return uses_allocator_construction_args(alloc, piecewise_construct, + tuple<>{}, tuple<>{}); +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{uses_allocator_construction_args}}% +\begin{itemdecl} +template + auto uses_allocator_construction_args(const Alloc& alloc, U&& u, V&& v) -> @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a specialization of \tcode{pair}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +return uses_allocator_construction_args(alloc, piecewise_construct, + forward_as_tuple(std::forward(u)), + forward_as_tuple(std::forward(v))); +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{uses_allocator_construction_args}}% +\begin{itemdecl} +template + auto uses_allocator_construction_args(const Alloc& alloc, const pair& pr) -> @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a specialization of \tcode{pair}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +return uses_allocator_construction_args(alloc, piecewise_construct, + forward_as_tuple(pr.first), + forward_as_tuple(pr.second)); +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{uses_allocator_construction_args}}% +\begin{itemdecl} +template + auto uses_allocator_construction_args(const Alloc& alloc, pair&& pr) -> @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a specialization of \tcode{pair}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +return uses_allocator_construction_args(alloc, piecewise_construct, + forward_as_tuple(std::move(pr).first), + forward_as_tuple(std::move(pr).second)); +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{make_obj_using_allocator}}% +\begin{itemdecl} +template + T make_obj_using_allocator(const Alloc& alloc, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return make_from_tuple(uses_allocator_construction_args( + alloc, std::forward(args)...)); +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{uninitialized_construct_using_allocator}}% +\begin{itemdecl} +template + T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return ::new(static_cast(p)) + T(make_obj_using_allocator(alloc, std::forward(args)...)); +\end{codeblock} +\end{itemdescr} + \rSec2[allocator.traits]{Allocator traits} \pnum @@ -11612,18 +11837,6 @@ template void construct(T* p, Args&&... args); - template - void construct(pair* p, piecewise_construct_t, - tuple x, tuple y); - template - void construct(pair* p); - template - void construct(pair* p, U&& x, V&& y); - template - void construct(pair* p, const pair& pr); - template - void construct(pair* p, pair&& pr); - template void destroy(T* p); @@ -11729,13 +11942,10 @@ \begin{itemdescr} \pnum -\requires +\mandates Uses-allocator construction of \tcode{T} with allocator \tcode{*this} (see~\ref{allocator.uses.construction}) and constructor arguments \tcode{std::forward(args)...} is well-formed. -\begin{note} -Uses-allocator construction is always well-formed -for types that do not use allocators.\end{note} \pnum \effects @@ -11747,163 +11957,6 @@ \pnum \throws Nothing unless the constructor for \tcode{T} throws. - -\pnum -\remarks -This function shall not participate in overload resolution if -\tcode{T} is a specialization of \tcode{pair}. -\end{itemdescr} - -\indexlibrarymember{construct}{polymorphic_allocator}% -\begin{itemdecl} -template - void construct(pair* p, piecewise_construct_t, tuple x, tuple y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\begin{note} -This member function and the \tcode{construct} member functions that follow -are overloads for piecewise construction of pairs\iref{pairs.pair}. -\end{note} - -\pnum -\effects -Let \tcode{xprime} be a \tcode{tuple} constructed from \tcode{x} -according to the appropriate rule from the following list. -\begin{note} -The following description can be summarized as -constructing a \tcode{pair} object -in the storage whose address is represented by \tcode{p}, -as if by separate uses-allocator construction -with allocator \tcode{*this}\iref{allocator.uses.construction} -of \tcode{p->first} using the elements of \tcode{x} -and \tcode{p->second} using the elements of \tcode{y}. -\end{note} -\begin{itemize} -\item -If \tcode{uses_allocator_v} is \tcode{false} -\\ -and -\tcode{is_constructible_v} is \tcode{true}, -\\ -then \tcode{xprime} is \tcode{x}. -\item -Otherwise, if \tcode{uses_allocator_v} is \tcode{true} -\\ -and -\tcode{is_constructible_v} is \tcode{true}, -\\ -then \tcode{xprime} is \tcode{tuple_cat(make_tuple(allocator_arg, *this), std::move(x))}. -\item -Otherwise, if \tcode{uses_allocator_v} is \tcode{true} -\\ -and -\tcode{is_constructible_v} is \tcode{true}, -\\ -then \tcode{xprime} is \tcode{tuple_cat(std::move(x), make_tuple(*this))}. -\item -Otherwise the program is ill formed. -\end{itemize} -Let \tcode{yprime} be a tuple constructed from \tcode{y} -according to the appropriate rule from the following list: -\begin{itemize} -\item -If \tcode{uses_allocator_v} is \tcode{false} -\\ -and -\tcode{is_constructible_v} is \tcode{true}, -\\ -then \tcode{yprime} is \tcode{y}. -\item -Otherwise, if \tcode{uses_allocator_v} is \tcode{true} -\\ -and -\tcode{is_constructible_v} is \tcode{true}, -\\ -then \tcode{yprime} is \tcode{tuple_cat(make_tuple(allocator_arg, *this), std::move(y))}. -\item -Otherwise, if \tcode{uses_allocator_v} is \tcode{true} -\\ -and -\tcode{is_constructible_v} is \tcode{true}, -\\ -then -\tcode{yprime} is \tcode{tuple_cat(std::move(y), make_tuple(*this))}. -\item -Otherwise the program is ill formed. -\end{itemize} - -Then, using \tcode{piecewise_construct}, \tcode{xprime}, and \tcode{yprime} -as the constructor arguments, -this function constructs a \tcode{pair} object -in the storage whose address is represented by \tcode{p}. -\end{itemdescr} - -\indexlibrarymember{construct}{polymorphic_allocator}% -\begin{itemdecl} -template - void construct(pair* p); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -construct(p, piecewise_construct, tuple<>(), tuple<>()); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{construct}{polymorphic_allocator}% -\begin{itemdecl} -template - void construct(pair* p, U&& x, V&& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -construct(p, piecewise_construct, - forward_as_tuple(std::forward(x)), - forward_as_tuple(std::forward(y))); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{construct}{polymorphic_allocator}% -\begin{itemdecl} -template - void construct(pair* p, const pair& pr); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -construct(p, piecewise_construct, - forward_as_tuple(pr.first), - forward_as_tuple(pr.second)); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{construct}{polymorphic_allocator}% -\begin{itemdecl} -template - void construct(pair* p, pair&& pr); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -construct(p, piecewise_construct, - forward_as_tuple(std::forward(pr.first)), - forward_as_tuple(std::forward(pr.second))); -\end{codeblock} \end{itemdescr} \indexlibrarymember{destroy}{polymorphic_allocator}% @@ -12689,17 +12742,6 @@ template void construct(T* p, Args&&... args); - template - void construct(pair* p, piecewise_construct_t, - tuple x, tuple y); - template - void construct(pair* p); - template - void construct(pair* p, U&& x, V&& y); - template - void construct(pair* p, const pair& x); - template - void construct(pair* p, pair&& x); template void destroy(T* p); @@ -12963,173 +13005,15 @@ \begin{itemdescr} \pnum \effects -\begin{itemize} -\item If \tcode{uses_allocator_v} is \tcode{false} and -\tcode{is_constructible_v} is \tcode{true}, calls: -\begin{codeblock} -@\placeholdernc{OUTERMOST_ALLOC_TRAITS}@(*this)::construct( - @\placeholdernc{OUTERMOST}@(*this), p, std::forward(args)...) -\end{codeblock} - -\item Otherwise, if \tcode{uses_allocator_v} is \tcode{true} and -\tcode{is_constructible_v} is \tcode{true}, calls: -\begin{codeblock} -@\placeholdernc{OUTERMOST_ALLOC_TRAITS}@(*this)::construct( - @\placeholdernc{OUTERMOST}@(*this), p, allocator_arg, inner_allocator(), std::forward(args)...) -\end{codeblock} - -\item Otherwise, if \tcode{uses_allocator_v} is \tcode{true} and -\tcode{is_constructible_v} is \tcode{true}, calls: -\begin{codeblock} -@\placeholdernc{OUTERMOST_ALLOC_TRAITS}@(*this)::construct( - @\placeholdernc{OUTERMOST}@(*this), p, std::forward(args)..., inner_allocator()) -\end{codeblock} - -\item Otherwise, the program is ill-formed. -\begin{note} -An error will result if -\tcode{uses_allocator} evaluates to \tcode{true} but the specific constructor does not take an -allocator. This definition prevents a silent failure to pass an inner allocator to a -contained element. -\end{note} -\end{itemize} - -\pnum -\remarks -This function shall not participate in overload resolution if -\tcode{T} is a specialization of \tcode{pair}. -\end{itemdescr} - -\indexlibrarymember{construct}{scoped_allocator_adaptor}% -\begin{itemdecl} -template - void construct(pair* p, piecewise_construct_t, tuple x, tuple y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Constructs a \tcode{tuple} object \tcode{xprime} from \tcode{x} by the -following rules: -\begin{itemize} -\item If \tcode{uses_allocator_v} is \tcode{false} and -\tcode{is_constructible_v} is \tcode{true}, -then \tcode{xprime} is \tcode{tuple(std::move(x))}. - -\item Otherwise, if \tcode{uses_allocator_v} is \tcode{true} -and -\tcode{is_construct\-ible_v} -is -\tcode{true}, then \tcode{xprime} is: -\begin{codeblock} -tuple_cat( - tuple(allocator_arg, inner_allocator()), - tuple(std::move(x))) -\end{codeblock} - -\item Otherwise, if \tcode{uses_allocator_v} is -\tcode{true} and -\tcode{is_construct\-ible_v} is \tcode{true}, -then \tcode{xprime} is: -\begin{codeblock} -tuple_cat(tuple(std::move(x)), - tuple(inner_allocator())) -\end{codeblock} - -\item Otherwise, the program is ill-formed. -\end{itemize} -and constructs a \tcode{tuple} object \tcode{yprime} from \tcode{y} by the following rules: -\begin{itemize} -\item If \tcode{uses_allocator_v} is \tcode{false} and -\tcode{is_constructible_v} is \tcode{true}, then \tcode{yprime} is \tcode{tuple(std::move(y)}. - -\item Otherwise, if \tcode{uses_allocator_v} is \tcode{true} -and -\tcode{is_constructible_v} -is -\tcode{true}, then \tcode{yprime} is: -\begin{codeblock} -tuple_cat( - tuple(allocator_arg, inner_allocator()), - tuple(std::move(y))) -\end{codeblock} - -\item Otherwise, if \tcode{uses_allocator_v} is -\tcode{true} and -\tcode{is_constructible_v} is \tcode{true}, -then \tcode{yprime} is: -\begin{codeblock} -tuple_cat(tuple(std::move(y)), - tuple(inner_allocator())) -\end{codeblock} - -\item Otherwise, the program is ill-formed. -\end{itemize} -then calls: -\begin{codeblock} -@\placeholdernc{OUTERMOST_ALLOC_TRAITS}@(*this)::construct( - @\placeholdernc{OUTERMOST}@(*this), p, piecewise_construct, std::move(xprime), std::move(yprime)) -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{construct}{scoped_allocator_adaptor}% -\begin{itemdecl} -template - void construct(pair* p); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: -\begin{codeblock} -construct(p, piecewise_construct, tuple<>(), tuple<>()); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{construct}{scoped_allocator_adaptor}% -\begin{itemdecl} -template - void construct(pair* p, U&& x, V&& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: -\begin{codeblock} -construct(p, piecewise_construct, - forward_as_tuple(std::forward(x)), - forward_as_tuple(std::forward(y))); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{construct}{scoped_allocator_adaptor}% -\begin{itemdecl} -template - void construct(pair* p, const pair& x); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: -\begin{codeblock} -construct(p, piecewise_construct, - forward_as_tuple(x.first), - forward_as_tuple(x.second)); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{construct}{scoped_allocator_adaptor}% -\begin{itemdecl} -template - void construct(pair* p, pair&& x); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: +Equivalent to: \begin{codeblock} -construct(p, piecewise_construct, - forward_as_tuple(std::forward(x.first)), - forward_as_tuple(std::forward(x.second))); +apply([p, this](auto&&... newargs) { + @\placeholdernc{OUTERMOST_ALLOC_TRAITS}@(*this)::construct( + @\placeholdernc{OUTERMOST}@(*this), p, + std::forward(newargs)...); + }, + uses_allocator_construction_args(inner_allocator(), + std::forward(args)...)); \end{codeblock} \end{itemdescr}