20 Memory management library [mem]

20.2 Memory [memory]

20.2.8 uses_­allocator [allocator.uses]

20.2.8.2 Uses-allocator construction [allocator.uses.construction]

Uses-allocator construction with allocator alloc and constructor arguments args... refers to the construction of an object of type T such that alloc is passed to the constructor of T if T uses an allocator type compatible with alloc.
When applied to the construction of an object of type T, it is equivalent to initializing it with the value of the expression make_­obj_­using_­allocator<T>(alloc, args...), described below.
The following utility functions support three conventions for passing alloc to a constructor:
  • If T does not use an allocator compatible with alloc, then alloc is ignored.
  • Otherwise, if T has a constructor invocable as T(allocator_­arg, alloc, args...) (leading-allocator convention), then uses-allocator construction chooses this constructor form.
  • Otherwise, if T has a constructor invocable as T(args..., alloc) (trailing-allocator convention), then uses-allocator construction chooses this constructor form.
The 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 pair such that uses-allocator construction is applied individually to the first and second data members.
The make_­obj_­using_­allocator and uninitialized_­construct_­using_­allocator function templates apply the modified constructor arguments to construct an object of type T as a return value or in-place, respectively.
[Note 1:
For uses_­allocator_­construction_­args and make_­obj_­using_­allocator, type T is not deduced and must therefore be specified explicitly by the caller.
— end note]
template<class T, class Alloc, class... Args> constexpr auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) noexcept;
Constraints: T is not a specialization of pair.
Returns: A tuple value determined as follows:
  • If uses_­allocator_­v<T, Alloc> is false and is_­constructible_­v<T, Args...> is true, return forward_­as_­tuple(std​::​forward<Args>(args)...).
  • Otherwise, if uses_­allocator_­v<T, Alloc> is true and is_­constructible_­v<T, allocator_­arg_­t, const Alloc&, Args...> is true, return tuple<allocator_arg_t, const Alloc&, Args&&...>( allocator_arg, alloc, std::forward<Args>(args)...)
  • Otherwise, if uses_­allocator_­v<T, Alloc> is true and is_­constructible_­v<T, Args..., const Alloc&> is true, return forward_­as_­tuple(std​::​forward<Args>(args)..., alloc).
  • Otherwise, the program is ill-formed.
[Note 2:
This definition prevents a silent failure to pass the allocator to a constructor of a type for which uses_­allocator_­v<T, Alloc> is true.
— end note]
template<class T, class Alloc, class Tuple1, class Tuple2> constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, Tuple1&& x, Tuple2&& y) noexcept;
Constraints: T is a specialization of pair.
Effects: For T specified as pair<T1, T2>, equivalent to: return make_tuple( piecewise_construct, apply([&alloc](auto&&... args1) { return uses_allocator_construction_args<T1>( alloc, std::forward<decltype(args1)>(args1)...); }, std::forward<Tuple1>(x)), apply([&alloc](auto&&... args2) { return uses_allocator_construction_args<T2>( alloc, std::forward<decltype(args2)>(args2)...); }, std::forward<Tuple2>(y)));
template<class T, class Alloc> constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept;
Constraints: T is a specialization of pair.
Effects: Equivalent to: return uses_allocator_construction_args<T>(alloc, piecewise_construct, tuple<>{}, tuple<>{});
template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u, V&& v) noexcept;
Constraints: T is a specialization of pair.
Effects: Equivalent to: return uses_allocator_construction_args<T>(alloc, piecewise_construct, forward_as_tuple(std::forward<U>(u)), forward_as_tuple(std::forward<V>(v)));
template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, pair<U, V>& pr) noexcept; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, const pair<U, V>& pr) noexcept;
Constraints: T is a specialization of pair.
Effects: Equivalent to: return uses_allocator_construction_args<T>(alloc, piecewise_construct, forward_as_tuple(pr.first), forward_as_tuple(pr.second));
template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, pair<U, V>&& pr) noexcept; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, const pair<U, V>&& pr) noexcept;
Constraints: T is a specialization of pair.
Effects: Equivalent to: return uses_allocator_construction_args<T>(alloc, piecewise_construct, forward_as_tuple(get<0>(std::move(pr))), forward_as_tuple(get<1>(std::move(pr))));
template<class T, class Alloc, class U> constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u) noexcept;
Let FUN be the function template: template<class A, class B> void FUN(const pair<A, B>&);
Constraints: T is a specialization of pair, and the expression FUN(u) is not well-formed when considered as an unevaluated operand.
Let pair-constructor be an exposition-only class defined as follows:
class pair-constructor { using pair-type = remove_cv_t<T>; // exposition only constexpr auto do-construct(const pair-type& p) const { // exposition only return make_obj_using_allocator<pair-type>(alloc_, p); } constexpr auto do-construct(pair-type&& p) const { // exposition only return make_obj_using_allocator<pair-type>(alloc_, std::move(p)); } const Alloc& alloc_; // exposition only U& u_; // exposition only public: constexpr operator pair-type() const { return do-construct(std::forward<U>(u_)); } };
Returns: make_­tuple(pc), where pc is a pair-constructor object whose alloc_­ member is initialized with alloc and whose u_­ member is initialized with u.
template<class T, class Alloc, class... Args> constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args);
Effects: Equivalent to: return make_from_tuple<T>(uses_allocator_construction_args<T>( alloc, std::forward<Args>(args)...));
template<class T, class Alloc, class... Args> constexpr T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args);
Effects: Equivalent to: return apply([&]<class... U>(U&&... xs) { return construct_at(p, std::forward<U>(xs)...); }, uses_allocator_construction_args<T>(alloc, std::forward<Args>(args)...));