Otherwise, if uses_allocator_v<remove_cv_t<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<remove_cv_t<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;
Effects: 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;
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;
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;
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;
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, pair-like P>
constexpr auto uses_allocator_construction_args(const Alloc& alloc, P&& p) noexcept;
Constraints:
remove_cv_t<T> is a specialization of
pair and
remove_cvref_t<P> is not a specialization of
ranges::subrange. Effects: Equivalent to:
return uses_allocator_construction_args<T>(alloc, piecewise_construct,
forward_as_tuple(get<0>(std::forward<P>(p)),
forward_as_tuple(get<1>(std::forward<P>(p));
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:
remove_cv_t<T> is a specialization of
pair, and either:
- remove_cvref_t<U> is a specialization of ranges::subrange, or
- U does not satisfy pair-like 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>;
constexpr auto do-construct(const pair-type& p) const {
return make_obj_using_allocator<pair-type>(alloc_, p);
}
constexpr auto do-construct(pair-type&& p) const {
return make_obj_using_allocator<pair-type>(alloc_, std::move(p));
}
const Alloc& alloc_;
U& u_;
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).);
The class template
allocator_traits supplies a uniform interface to all
allocator types
. An allocator cannot be a non-class type, however, even if
allocator_traits
supplies the entire required interface
. [
Note 1:
Thus, it is always possible to create
a derived class from an allocator
. —
end note]
If a program declares
an explicit or partial specialization of
allocator_traits,
the program is ill-formed, no diagnostic required
.namespace std {
template<class Alloc> struct allocator_traits {
using allocator_type = Alloc;
using value_type = Alloc::value_type;
using pointer = see below;
using const_pointer = see below;
using void_pointer = see below;
using const_void_pointer = see below;
using difference_type = see below;
using size_type = see below;
using propagate_on_container_copy_assignment = see below;
using propagate_on_container_move_assignment = see below;
using propagate_on_container_swap = see below;
using is_always_equal = see below;
template<class T> using rebind_alloc = see below;
template<class T> using rebind_traits = allocator_traits<rebind_alloc<T>>;
static constexpr pointer allocate(Alloc& a, size_type n);
static constexpr pointer allocate(Alloc& a, size_type n, const_void_pointer hint);
static constexpr allocation_result<pointer, size_type>
allocate_at_least(Alloc& a, size_type n);
static constexpr void deallocate(Alloc& a, pointer p, size_type n);
template<class T, class. Args>
static constexpr void construct(Alloc& a, T* p, Args&&. args);
template<class T>
static constexpr void destroy(Alloc& a, T* p);
static constexpr size_type max_size(const Alloc& a) noexcept;
static constexpr Alloc select_on_container_copy_construction(const Alloc& rhs);
};
}
using pointer = see below;
using const_pointer = see below;
Type:
Alloc::const_pointer if
the
qualified-id Alloc::const_pointer is valid and denotes a
type (
[temp.deduct]); otherwise,
pointer_traits<pointer>::rebind<const value_type>. using void_pointer = see below;
Type:
Alloc::void_pointer if
the
qualified-id Alloc::void_pointer is valid and denotes a
type (
[temp.deduct]); otherwise,
pointer_traits<pointer>::rebind<void>. using const_void_pointer = see below;
Type:
Alloc::const_void_pointer if
the
qualified-id Alloc::const_void_pointer is valid and denotes a
type (
[temp.deduct]); otherwise,
pointer_traits<pointer>::rebind<const void>. using difference_type = see below;
Type:
Alloc::difference_type if
the
qualified-id Alloc::difference_type is valid and denotes a
type (
[temp.deduct]); otherwise,
pointer_traits<pointer>::difference_type. using size_type = see below;
Type:
Alloc::size_type if
the
qualified-id Alloc::size_type is valid and denotes a
type (
[temp.deduct]); otherwise,
make_unsigned_t<difference_type>. using propagate_on_container_copy_assignment = see below;
Type:
Alloc::propagate_on_container_copy_assignment if
the
qualified-id Alloc::propagate_on_container_copy_assignment is valid and denotes a
type (
[temp.deduct]); otherwise
false_type. using propagate_on_container_move_assignment = see below;
Type:
Alloc::propagate_on_container_move_assignment if
the
qualified-id Alloc::propagate_on_container_move_assignment is valid and denotes a
type (
[temp.deduct]); otherwise
false_type. using propagate_on_container_swap = see below;
Type:
Alloc::propagate_on_container_swap if
the
qualified-id Alloc::propagate_on_container_swap is valid and denotes a
type (
[temp.deduct]); otherwise
false_type. using is_always_equal = see below;
Type:
Alloc::is_always_equal if
the
qualified-id Alloc::is_always_equal
is valid and denotes a type (
[temp.deduct]);
otherwise
is_empty<Alloc>::type. template<class T> using rebind_alloc = see below;
Alias template:
Alloc::rebind<T>::other if
the
qualified-id Alloc::rebind<T>::other is valid and denotes a
type (
[temp.deduct]); otherwise,
Alloc<T, Args> if
Alloc is a class template instantiation
of the form
Alloc<U, Args>, where
Args is zero or more type arguments;
otherwise, the instantiation of
rebind_alloc is ill-formed
. static constexpr pointer allocate(Alloc& a, size_type n);
static constexpr pointer allocate(Alloc& a, size_type n, const_void_pointer hint);
Returns:
a.allocate(n, hint) if that expression is well-formed; otherwise,
a.allocate(n). static constexpr allocation_result<pointer, size_type> allocate_at_least(Alloc& a, size_type n);
Returns:
a.allocate_at_least(n) if that expression is well-formed;
otherwise,
{a.allocate(n), n}. static constexpr void deallocate(Alloc& a, pointer p, size_type n);
template<class T, class. Args>
static constexpr void construct(Alloc& a, T* p, Args&&. args);
Effects: Calls
a.construct(p, std::forward<Args>(args).)
if that call is well-formed;
otherwise, invokes
construct_at(p, std::forward<Args>(args).). template<class T>
static constexpr void destroy(Alloc& a, T* p);
Effects: Calls
a.destroy(p) if that call is well-formed; otherwise, invokes
destroy_at(p). static constexpr size_type max_size(const Alloc& a) noexcept;
Returns:
a.max_size() if that expression is well-formed; otherwise,
numeric_limits<size_type>::max() / sizeof(value_type). static constexpr Alloc select_on_container_copy_construction(const Alloc& rhs);
Returns:
rhs.select_on_container_copy_construction() if that expression is
well-formed; otherwise,
rhs. The class template
allocation_result has
the template parameters, data members, and special members specified above
. It has no base classes or members other than those specified
.namespace std {
template<class T> class allocator {
public:
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using propagate_on_container_move_assignment = true_type;
constexpr allocator() noexcept;
constexpr allocator(const allocator&) noexcept;
template<class U> constexpr allocator(const allocator<U>&) noexcept;
constexpr ~allocator();
constexpr allocator& operator=(const allocator&) = default;
constexpr T* allocate(size_t n);
constexpr allocation_result<T*> allocate_at_least(size_t n);
constexpr void deallocate(T* p, size_t n);
};
}
allocator_traits<allocator<T>>::is_always_equal::value
is
true for any
T. Except for the destructor, member functions of the default allocator shall not introduce
data races (
[intro.multithread]) as a result of concurrent calls to those member
functions from different threads
. Calls to these functions that allocate or deallocate a
particular unit of storage shall occur in a single total order, and each such
deallocation call shall happen before the next allocation (if any) in this order
.constexpr T* allocate(size_t n);
Throws:
bad_array_new_length if
numeric_limits<size_t>::max() / sizeof(T) < n, or
bad_alloc if the storage cannot be obtained
. Remarks: The storage for the array
is obtained by calling
::operator new (
[new.delete]),
but it is unspecified when or how often this
function is called
. This function starts the lifetime of the array object,
but not that of any of the array elements
.constexpr allocation_result<T*> allocate_at_least(size_t n);
Returns:
allocation_result<T*>{ptr, count},
where
ptr is a pointer to
the initial element of an array of
count T and
count ≥ n. Throws:
bad_array_new_length
if
numeric_limits<size_t>::max() / sizeof(T) < n,
or
bad_alloc if the storage cannot be obtained
. Remarks: The storage for the array is obtained by calling
::operator new,
but it is unspecified when or how often this function is called
. This function starts the lifetime of the array object,
but not that of any of the array elements
.constexpr void deallocate(T* p, size_t n);
Preconditions:
If
p is memory that was obtained by a call to
allocate_at_least,
let
ret be the value returned and
req be the value passed as the first argument to that call
. p is equal to
ret.ptr and
n is a value such that
req ≤ n ≤ ret.count. Otherwise,
p is a pointer value obtained from
allocate. n equals the value passed as the first argument
to the invocation of
allocate which returned
p. Remarks: Uses
::operator delete (
[new.delete]),
but it is unspecified
when this function is called
.