Difference between revisions of "cpp/memory/scoped allocator adaptor/construct"
Andreas Krug (Talk | contribs) m (fmt, {{c}}) |
(Overhauled the description: 1. Refers to exposition-only “outermost-construct” for the real construction operations. 2. Added the exposition-only helper “concat-args” to remove the xprime/yprime duplication. 3. Added LWG2203/LWG2586 DRs.) |
||
Line 9: | Line 9: | ||
{{dcl|num=2|until=c++20| | {{dcl|num=2|until=c++20| | ||
template< class T1, class T2, class... Args1, class... Args2 > | template< class T1, class T2, class... Args1, class... Args2 > | ||
− | void construct( std::pair<T1, T2>* p, | + | void construct( std::pair<T1, T2>* p, std::piecewise_construct_t, |
− | + | std::tuple<Args1...> x, std::tuple<Args2...> y ); | |
− | std::tuple<Args1...> x, | + | |
− | + | ||
}} | }} | ||
{{dcl|num=3|until=c++20| | {{dcl|num=3|until=c++20| | ||
Line 30: | Line 28: | ||
void construct( std::pair<T1, T2>* p, std::pair<U, V>&& xy ); | void construct( std::pair<T1, T2>* p, std::pair<U, V>&& xy ); | ||
}} | }} | ||
− | {{dcl|num=7|until=c++20| | + | {{dcl h|Helper function templates}} |
− | template< class | + | {{dcla|num=7|until=c++20|expos=yes| |
− | + | template < class T, class... Args > | |
+ | std::tuple</* see below */> /*concat-args*/( std::tuple<Args...>&& tup ); | ||
}} | }} | ||
{{dcl end}} | {{dcl end}} | ||
− | Constructs an object in allocated, but not initialized storage pointed to by {{c|p}} using | + | Constructs an object in allocated, but not initialized storage pointed to by {{c|p}} using the outer allocator and the provided constructor arguments. If the object is of a type that itself uses allocators{{rev inl|until=c++20|, or if it is {{lc|std::pair}}}}, passes the inner allocator down to the constructed object. |
− | + | @1@ Constructs an object of type {{tt|T}} by [[cpp/memory/uses_allocator#Uses-allocator_construction|uses-allocator construction]] at the uninitialized memory location indicated by {{c|p}} using the outermost allocator. | |
+ | {{rev begin}} | ||
+ | {{rev|until=c++20| | ||
+ | Given {{c|std::uses_allocator<T, inner_allocator_type>::value}} as {{c|uses_inner}}: | ||
+ | * If {{c|uses_inner}} is {{c|false}} and {{c|std::is_constructible<T, Args...>::value}} is {{c|true}}, calls {{box|{{rlpsi|helpers#outermost-construct}}{{sep}}{{c/core|(p, std::forward<Args>(args)...)}}}}. | ||
+ | * Otherwise, if {{c|uses_inner}} and {{c multi|std::is_constructible<T, std::allocator_arg_t,| inner_allocator_type&,| Args...>::value}} are both {{c|true}}, calls {{box|{{rlpsi|helpers#outermost-construct}}{{sep}}{{c/core|(p, std::allocator_arg,}}<br>{{nbspt|20}}{{c/core|inner_allocator(),}}<br>{{nbspt|20}}{{c/core|std::forward<Args>(args)...)}}}}. | ||
+ | * Otherwise, if {{c|uses_inner}} and {{c|std::is_constructible<T, Args..., inner_allocator_type&>::value}} are both {{c|true}}, calls {{box|{{rlpsi|helpers#outermost-construct}}{{sep}}{{c/core|(p, std::forward<Args>(args)..., inner_allocator())}}}}. | ||
+ | * Otherwise, the program is ill-formed. | ||
− | + | {{cpp/enable if|{{tt|T}} is not a specialization of {{lc|std::pair}}}}. | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
}} | }} | ||
− | + | {{rev|since=c++20| | |
− | {{c| | + | Equivalent to {{box| |
− | + | {{c/core|std::apply}}<br> | |
− | {{c | + | {{c/core|(}}<br> |
− | | | + | {{nbspt|4}}{{c/core|[p, this](auto&&... newargs)}}<br> |
− | + | {{nbspt|4}}{{c/core|{}}<br> | |
+ | {{nbspt|8}}{{rlpsi|helpers#outermost-construct}}<br> | ||
+ | {{nbspt|12}}{{c/core|(p, std::forward<decltype(newargs)>(newargs)...);}}<br> | ||
+ | {{nbspt|4}}{{c/core|},}}<br> | ||
+ | {{nbspt|4}}{{c/core|std::uses_allocator_construction_args}}<br> | ||
+ | {{nbspt|8}}{{c/core|(inner_allocator(), std::forward<Args>(args)...)}}<br> | ||
+ | {{c/core|);}} | ||
}}. | }}. | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
}} | }} | ||
+ | {{rev end}} | ||
− | @ | + | @2-6@ Constructs a {{lc|std::pair}} object by [[cpp/memory/uses_allocator#Uses-allocator_construction|uses-allocator construction]] at the uninitialized memory location indicated by {{c|p}} using the outermost allocator. |
− | {{ | + | |
− | + | ||
− | @ | + | :@2@ Let {{c|xprime}} be {{box|{{tti|concat-args}}{{sep}}{{c/core|<T1>(std::move(x))}}}}, {{c|yprime}} be {{box|{{tti|concat-args}}{{sep}}{{c/core|<T2>(std::move(y))}}}}, calls {{box|{{rlpsi|helpers#outermost-construct}}{{sep}}{{c/core|(p, std::piecewise_construct, std::move(xprime), std::move(yprime))}}}}. |
− | {{c | + | |
− | | | + | |
− | | | + | |
− | }} | + | |
− | @ | + | :@3@ Equivalent to {{c|construct(p, std::piecewise_construct, std::tuple<>(), std::tuple<>());}}. |
− | {{c | + | |
− | |construct(p, std::piecewise_construct, std:: | + | |
− | + | ||
− | }} | + | |
− | @6@ Equivalent to | + | :@4-6@ Equivalent to {{c multi|construct(p, std::piecewise_construct,| std::forward_as_tuple(xarg), std::forward_as_tuple(yarg));}}, where {{c|xarg}} and {{c|yarg}} are defined as follows: |
− | {{c multi | + | {|class="wikitable" style="text-align: center;" |
− | |construct(p, std::piecewise_construct, | + | !{{nbsp}}Overload{{nbsp}} |
− | | | + | !{{normal|{{c|xarg}}}} |
− | | | + | !{{normal|{{c|yarg}}}} |
− | }} | + | |- |
+ | |{{v|4}} | ||
+ | |{{c|std::forward<U>(x)}} | ||
+ | |{{c|std::forward<V>(y)}} | ||
+ | |- | ||
+ | |{{v|5}} | ||
+ | |{{c|xy.first}} | ||
+ | |{{c|xy.second}} | ||
+ | |- | ||
+ | |{{v|6}} | ||
+ | |{{c|std::forward<U>(xy.first)}} | ||
+ | |{{c|std::forward<V>(xy.second)}} | ||
+ | |} | ||
− | @7@ {{cpp/ | + | @7@ Merges the arguments contained in {{c|tup}} and additional arguments required by [[cpp/memory/uses_allocator#Uses-allocator_construction|uses-allocator construction]] of an object of type {{tt|T}}. |
− | {{c | + | @@ Given {{c|std::uses_allocator<T, inner_allocator_type>::value}} as {{c|uses_inner}}: |
− | | | + | * If {{c|uses_inner}} is {{c|false}} and {{c|std::is_constructible<T, Args...>::value}} is {{c|true}}, returns {{c|std::tuple<Args&&...>(std::move(tup))}}. |
− | | | + | * Otherwise, if {{c|uses_inner}} and {{c multi|std::is_constructible<T, std::allocator_arg_t,| inner_allocator_type&,| Args...>::value}} are both {{c|true}}, returns {{c multi|std::tuple_cat(std::tuple<std::allocator_arg_t, inner_allocator_type&>| (std::allocator_arg, inner_allocator()),| std::tuple<Args&&...>(std::move(tup)))}}. |
− | }}, | + | * Otherwise, if {{c|uses_inner}} and {{c|std::is_constructible<T, Args..., inner_allocator_type&>::value}} are both {{c|true}}, returns {{c multi|std::tuple_cat(std::tuple<Args&&...>(std::move(tup)),| std::tuple<inner_allocator_type&>(inner_allocator())}}. |
− | {{c| | + | * Otherwise, the program is ill-formed. |
− | + | ||
− | + | ||
===Parameters=== | ===Parameters=== | ||
{{par begin}} | {{par begin}} | ||
{{par|p|pointer to allocated, but not initialized storage}} | {{par|p|pointer to allocated, but not initialized storage}} | ||
− | {{par|args | + | {{par|args|the constructor arguments to pass to the constructor of {{tt|T}}}} |
{{par|x|the constructor arguments to pass to the constructor of {{tt|T1}}}} | {{par|x|the constructor arguments to pass to the constructor of {{tt|T1}}}} | ||
{{par|y|the constructor arguments to pass to the constructor of {{tt|T2}}}} | {{par|y|the constructor arguments to pass to the constructor of {{tt|T2}}}} | ||
{{par|xy|the pair whose two members are the constructor arguments for {{tt|T1}} and {{tt|T2}}}} | {{par|xy|the pair whose two members are the constructor arguments for {{tt|T1}} and {{tt|T2}}}} | ||
− | {{par| | + | {{par|tup|the arguments to be merged}} |
{{par end}} | {{par end}} | ||
− | |||
− | |||
− | |||
===Notes=== | ===Notes=== | ||
− | This function is called (through {{lc|std::allocator_traits}}) by any allocator-aware object, such as {{lc|std::vector}}, that was given a {{lc|std::scoped_allocator_adaptor}} as the allocator to use. Since {{tt| | + | This function is called (through {{lc|std::allocator_traits}}) by any allocator-aware object, such as {{lc|std::vector}}, that was given a {{lc|std::scoped_allocator_adaptor}} as the allocator to use. Since {{tt|inner_allocator_type}} is itself a specialization of {{lc|std::scoped_allocator_adaptor}}, this function will also be called when the allocator-aware objects constructed through this function start constructing their own members. |
===Defect reports=== | ===Defect reports=== | ||
{{dr list begin}} | {{dr list begin}} | ||
− | {{dr list item|wg=lwg|dr= | + | {{dr list item|wg=lwg|dr=2203|std=C++11|before=inner allocators were obtained by value-initializing<br>an {{tt|inner_allocator_type}} object|after=obtained by calling {{rlpf|inner_allocator}}}} |
− | {{dr list item|paper=P0475R1|std=C++11|before= | + | {{dr list item|wg=lwg|dr=2511|paper=P0475R1|std=C++11|before={{tti|concat-args}} might copy elements of {{lc|std::tuple}}s|after=eliminated all element copy operations}} |
− | {{dr list item|wg=lwg|dr= | + | {{dr list item|wg=lwg|dr=2586|std=C++11|before=only constructions from<br>{{tt|inner_allocator_type}} rvalues were checked|after=checks constructions from non-const<br>{{tt|inner_allocator_type}} lvalues instead}} |
+ | {{dr list item|wg=lwg|dr=2975|std=C++11|before=overload {{v|1}} was not constrianted|after=constrained to refuse {{lc|std::pair}}}} | ||
{{dr list end}} | {{dr list end}} | ||
Revision as of 23:54, 13 November 2024
Defined in header <scoped_allocator>
|
||
template< class T, class... Args > void construct( T* p, Args&&... args ); |
(1) | |
template< class T1, class T2, class... Args1, class... Args2 > void construct( std::pair<T1, T2>* p, std::piecewise_construct_t, |
(2) | (until C++20) |
template< class T1, class T2 > void construct( std::pair<T1, T2>* p ); |
(3) | (until C++20) |
template< class T1, class T2, class U, class V > void construct( std::pair<T1, T2>* p, U&& x, V&& y ); |
(4) | (until C++20) |
(5) | (until C++20) | |
(6) | (until C++20) | |
Helper function templates |
||
template < class T, class... Args > std::tuple</* see below */> /*concat-args*/( std::tuple<Args...>&& tup ); |
(7) | (exposition only*) (until C++20) |
Constructs an object in allocated, but not initialized storage pointed to by p using the outer allocator and the provided constructor arguments. If the object is of a type that itself uses allocators, or if it is std::pair(until C++20), passes the inner allocator down to the constructed object.
T
by uses-allocator construction at the uninitialized memory location indicated by p using the outermost allocator.
Given std::uses_allocator<T, inner_allocator_type>::value as uses_inner:
This overload participates in overload resolution only if |
(until C++20) |
Equivalent to
std::apply |
(since C++20) |
concat-args
<T1>(std::move(x)), yprime be concat-args
<T2>(std::move(y)), calls outermost-construct
(p, std::piecewise_construct, std::move(xprime), std::move(yprime)).std::forward_as_tuple(xarg), std::forward_as_tuple(yarg));, where xarg and yarg are defined as follows:
Overload | xarg | yarg |
---|---|---|
(4) | std::forward<U>(x) | std::forward<V>(y) |
(5) | xy.first | xy.second |
(6) | std::forward<U>(xy.first) | std::forward<V>(xy.second) |
T
.- If uses_inner is false and std::is_constructible<T, Args...>::value is true, returns std::tuple<Args&&...>(std::move(tup)).
- Otherwise, if uses_inner and std::is_constructible<T, std::allocator_arg_t,
inner_allocator_type&,
Args...>::value are both true, returns std::tuple_cat(std::tuple<std::allocator_arg_t, inner_allocator_type&>
(std::allocator_arg, inner_allocator()),
std::tuple<Args&&...>(std::move(tup))). - Otherwise, if uses_inner and std::is_constructible<T, Args..., inner_allocator_type&>::value are both true, returns std::tuple_cat(std::tuple<Args&&...>(std::move(tup)),
std::tuple<inner_allocator_type&>(inner_allocator()). - Otherwise, the program is ill-formed.
Contents |
Parameters
p | - | pointer to allocated, but not initialized storage |
args | - | the constructor arguments to pass to the constructor of T
|
x | - | the constructor arguments to pass to the constructor of T1
|
y | - | the constructor arguments to pass to the constructor of T2
|
xy | - | the pair whose two members are the constructor arguments for T1 and T2
|
tup | - | the arguments to be merged |
Notes
This function is called (through std::allocator_traits) by any allocator-aware object, such as std::vector, that was given a std::scoped_allocator_adaptor as the allocator to use. Since inner_allocator_type
is itself a specialization of std::scoped_allocator_adaptor, this function will also be called when the allocator-aware objects constructed through this function start constructing their own members.
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
LWG 2203 | C++11 | inner allocators were obtained by value-initializing an inner_allocator_type object
|
obtained by calling inner_allocator()
|
LWG 2511 (P0475R1) |
C++11 | concat-args might copy elements of std::tuples
|
eliminated all element copy operations |
LWG 2586 | C++11 | only constructions frominner_allocator_type rvalues were checked
|
checks constructions from non-constinner_allocator_type lvalues instead
|
LWG 2975 | C++11 | overload (1) was not constrianted | constrained to refuse std::pair |
See also
[static] |
constructs an object in the allocated storage (function template) |
(until C++20) |
constructs an object in allocated storage (public member function of std::allocator<T> )
|