Skip to content

Commit

Permalink
[libc++] [P1518R2] Better CTAD behavior for containers with allocators.
Browse files Browse the repository at this point in the history
P1518 does the following in C++23 but we'll just do it in C++17 as well:
- Stop requiring `Alloc` to be an allocator on some container-adaptor deduction guides
- Stop deducing from `Allocator` on some sequence container constructors
- Stop deducing from `Allocator` on some other container constructors (libc++ already did this)

The affected constructors are the "allocator-extended" versions of
constructors where the non-allocator arguments are already sufficient
to deduce the allocator type. For example,

    std::pmr::vector<int> v1;
    std::vector v2(v1, std::pmr::new_delete_resource());
    std::stack s2(v1, std::pmr::new_delete_resource());

Differential Revision: https://reviews.llvm.org/D97742
  • Loading branch information
Arthur O'Dwyer committed Jun 18, 2021
1 parent bdd5da9 commit dd15c27
Show file tree
Hide file tree
Showing 18 changed files with 421 additions and 73 deletions.
2 changes: 2 additions & 0 deletions libcxx/docs/Cxx2bStatusPaperStatus.csv
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@
"`P2212R2 <https://wg21.link/P2212R2>`__","LWG","Relax Requirements for time_point::clock","February 2021","",""
"`P2259R1 <https://wg21.link/P2259R1>`__","LWG","Repairing input range adaptors and counted_iterator","February 2021","",""
"","","","","",""
"`P1518R2 <https://wg21.link/P1518R2>`__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0"
"","","","","",""
8 changes: 4 additions & 4 deletions libcxx/include/deque
Original file line number Diff line number Diff line change
Expand Up @@ -1317,7 +1317,7 @@ public:
deque(_InputIter __f, _InputIter __l, const allocator_type& __a,
typename enable_if<__is_cpp17_input_iterator<_InputIter>::value>::type* = 0);
deque(const deque& __c);
deque(const deque& __c, const allocator_type& __a);
deque(const deque& __c, const __identity_t<allocator_type>& __a);

deque& operator=(const deque& __c);

Expand All @@ -1331,7 +1331,7 @@ public:
_LIBCPP_INLINE_VISIBILITY
deque(deque&& __c) _NOEXCEPT_(is_nothrow_move_constructible<__base>::value);
_LIBCPP_INLINE_VISIBILITY
deque(deque&& __c, const allocator_type& __a);
deque(deque&& __c, const __identity_t<allocator_type>& __a);
_LIBCPP_INLINE_VISIBILITY
deque& operator=(deque&& __c)
_NOEXCEPT_(__alloc_traits::propagate_on_container_move_assignment::value &&
Expand Down Expand Up @@ -1660,7 +1660,7 @@ deque<_Tp, _Allocator>::deque(const deque& __c)
}

template <class _Tp, class _Allocator>
deque<_Tp, _Allocator>::deque(const deque& __c, const allocator_type& __a)
deque<_Tp, _Allocator>::deque(const deque& __c, const __identity_t<allocator_type>& __a)
: __base(__a)
{
__append(__c.begin(), __c.end());
Expand Down Expand Up @@ -1703,7 +1703,7 @@ deque<_Tp, _Allocator>::deque(deque&& __c)

template <class _Tp, class _Allocator>
inline
deque<_Tp, _Allocator>::deque(deque&& __c, const allocator_type& __a)
deque<_Tp, _Allocator>::deque(deque&& __c, const __identity_t<allocator_type>& __a)
: __base(_VSTD::move(__c), __a)
{
if (__a != __c.__alloc())
Expand Down
8 changes: 4 additions & 4 deletions libcxx/include/forward_list
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ public:
__is_cpp17_input_iterator<_InputIterator>::value
>::type* = nullptr);
forward_list(const forward_list& __x);
forward_list(const forward_list& __x, const allocator_type& __a);
forward_list(const forward_list& __x, const __identity_t<allocator_type>& __a);

forward_list& operator=(const forward_list& __x);

Expand All @@ -690,7 +690,7 @@ public:
forward_list(forward_list&& __x)
_NOEXCEPT_(is_nothrow_move_constructible<base>::value)
: base(_VSTD::move(__x)) {}
forward_list(forward_list&& __x, const allocator_type& __a);
forward_list(forward_list&& __x, const __identity_t<allocator_type>& __a);

forward_list(initializer_list<value_type> __il);
forward_list(initializer_list<value_type> __il, const allocator_type& __a);
Expand Down Expand Up @@ -979,7 +979,7 @@ forward_list<_Tp, _Alloc>::forward_list(const forward_list& __x)

template <class _Tp, class _Alloc>
forward_list<_Tp, _Alloc>::forward_list(const forward_list& __x,
const allocator_type& __a)
const __identity_t<allocator_type>& __a)
: base(__a)
{
insert_after(cbefore_begin(), __x.begin(), __x.end());
Expand All @@ -1000,7 +1000,7 @@ forward_list<_Tp, _Alloc>::operator=(const forward_list& __x)
#ifndef _LIBCPP_CXX03_LANG
template <class _Tp, class _Alloc>
forward_list<_Tp, _Alloc>::forward_list(forward_list&& __x,
const allocator_type& __a)
const __identity_t<allocator_type>& __a)
: base(_VSTD::move(__x), __a)
{
if (base::__alloc() != __x.__alloc())
Expand Down
8 changes: 4 additions & 4 deletions libcxx/include/list
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,7 @@ public:
typename enable_if<__is_cpp17_input_iterator<_InpIter>::value>::type* = 0);

list(const list& __c);
list(const list& __c, const allocator_type& __a);
list(const list& __c, const __identity_t<allocator_type>& __a);
_LIBCPP_INLINE_VISIBILITY
list& operator=(const list& __c);
#ifndef _LIBCPP_CXX03_LANG
Expand All @@ -904,7 +904,7 @@ public:
list(list&& __c)
_NOEXCEPT_(is_nothrow_move_constructible<__node_allocator>::value);
_LIBCPP_INLINE_VISIBILITY
list(list&& __c, const allocator_type& __a);
list(list&& __c, const __identity_t<allocator_type>& __a);
_LIBCPP_INLINE_VISIBILITY
list& operator=(list&& __c)
_NOEXCEPT_(
Expand Down Expand Up @@ -1286,7 +1286,7 @@ list<_Tp, _Alloc>::list(const list& __c)
}

template <class _Tp, class _Alloc>
list<_Tp, _Alloc>::list(const list& __c, const allocator_type& __a)
list<_Tp, _Alloc>::list(const list& __c, const __identity_t<allocator_type>& __a)
: base(__a)
{
#if _LIBCPP_DEBUG_LEVEL == 2
Expand Down Expand Up @@ -1333,7 +1333,7 @@ inline list<_Tp, _Alloc>::list(list&& __c)

template <class _Tp, class _Alloc>
inline
list<_Tp, _Alloc>::list(list&& __c, const allocator_type& __a)
list<_Tp, _Alloc>::list(list&& __c, const __identity_t<allocator_type>& __a)
: base(__a)
{
#if _LIBCPP_DEBUG_LEVEL == 2
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/queue
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ queue(_Container)
template<class _Container,
class _Alloc,
class = _EnableIf<!__is_allocator<_Container>::value>,
class = _EnableIf<__is_allocator<_Alloc>::value>
class = _EnableIf<uses_allocator<_Container, _Alloc>::value>
>
queue(_Container, _Alloc)
-> queue<typename _Container::value_type, _Container>;
Expand Down Expand Up @@ -554,7 +554,7 @@ template<class _Compare,
class _Alloc,
class = _EnableIf<!__is_allocator<_Compare>::value>,
class = _EnableIf<!__is_allocator<_Container>::value>,
class = _EnableIf<__is_allocator<_Alloc>::value>
class = _EnableIf<uses_allocator<_Container, _Alloc>::value>
>
priority_queue(_Compare, _Container, _Alloc)
-> priority_queue<typename _Container::value_type, _Container, _Compare>;
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/stack
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ stack(_Container)
template<class _Container,
class _Alloc,
class = _EnableIf<!__is_allocator<_Container>::value>,
class = _EnableIf<__is_allocator<_Alloc>::value>
class = _EnableIf<uses_allocator<_Container, _Alloc>::value>
>
stack(_Container, _Alloc)
-> stack<typename _Container::value_type, _Container>;
Expand Down
12 changes: 6 additions & 6 deletions libcxx/include/vector
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ public:
}

vector(const vector& __x);
vector(const vector& __x, const allocator_type& __a);
vector(const vector& __x, const __identity_t<allocator_type>& __a);
_LIBCPP_INLINE_VISIBILITY
vector& operator=(const vector& __x);

Expand All @@ -577,7 +577,7 @@ public:
#endif

_LIBCPP_INLINE_VISIBILITY
vector(vector&& __x, const allocator_type& __a);
vector(vector&& __x, const __identity_t<allocator_type>& __a);
_LIBCPP_INLINE_VISIBILITY
vector& operator=(vector&& __x)
_NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value));
Expand Down Expand Up @@ -1261,7 +1261,7 @@ vector<_Tp, _Allocator>::vector(const vector& __x)
}

template <class _Tp, class _Allocator>
vector<_Tp, _Allocator>::vector(const vector& __x, const allocator_type& __a)
vector<_Tp, _Allocator>::vector(const vector& __x, const __identity_t<allocator_type>& __a)
: __base(__a)
{
#if _LIBCPP_DEBUG_LEVEL == 2
Expand Down Expand Up @@ -1299,7 +1299,7 @@ vector<_Tp, _Allocator>::vector(vector&& __x)

template <class _Tp, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY
vector<_Tp, _Allocator>::vector(vector&& __x, const allocator_type& __a)
vector<_Tp, _Allocator>::vector(vector&& __x, const __identity_t<allocator_type>& __a)
: __base(__a)
{
#if _LIBCPP_DEBUG_LEVEL == 2
Expand Down Expand Up @@ -2261,7 +2261,7 @@ public:
#else
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value);
#endif
vector(vector&& __v, const allocator_type& __a);
vector(vector&& __v, const __identity_t<allocator_type>& __a);
_LIBCPP_INLINE_VISIBILITY
vector& operator=(vector&& __v)
_NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value));
Expand Down Expand Up @@ -2887,7 +2887,7 @@ inline _LIBCPP_INLINE_VISIBILITY vector<bool, _Allocator>::vector(vector&& __v)
}

template <class _Allocator>
vector<bool, _Allocator>::vector(vector&& __v, const allocator_type& __a)
vector<bool, _Allocator>::vector(vector&& __v, const __identity_t<allocator_type>& __a)
: __begin_(nullptr),
__size_(0),
__cap_alloc_(0, __a)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,24 @@ int main(int, char**)
assert(m.get_allocator().get_id() == 45);
}

{
// Examples from LWG3025
std::map m{std::pair{1, 1}, {2, 2}, {3, 3}};
ASSERT_SAME_TYPE(decltype(m), std::map<int, int>);

std::map m2{m.begin(), m.end()};
ASSERT_SAME_TYPE(decltype(m2), std::map<int, int>);
}

{
// Examples from LWG3531
std::map m1{{std::pair{1, 2}, {3, 4}}, std::less<int>()};
ASSERT_SAME_TYPE(decltype(m1), std::map<int, int>);

using value_type = std::pair<const int, int>;
std::map m2{{value_type{1, 2}, {3, 4}}, std::less<int>()};
ASSERT_SAME_TYPE(decltype(m2), std::map<int, int>);
}

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,24 @@ int main(int, char**)
assert(m.get_allocator().get_id() == 45);
}

{
// Examples from LWG3025
std::multimap m{std::pair{1, 1}, {2, 2}, {3, 3}};
ASSERT_SAME_TYPE(decltype(m), std::multimap<int, int>);

std::multimap m2{m.begin(), m.end()};
ASSERT_SAME_TYPE(decltype(m2), std::multimap<int, int>);
}

{
// Examples from LWG3531
std::multimap m1{{std::pair{1, 2}, {3, 4}}, std::less<int>()};
ASSERT_SAME_TYPE(decltype(m1), std::multimap<int, int>);

using value_type = std::pair<const int, int>;
std::multimap m2{{value_type{1, 2}, {3, 4}}, std::less<int>()};
ASSERT_SAME_TYPE(decltype(m2), std::multimap<int, int>);
}

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,76 @@ int main(int, char**)
}

{
// This one is odd - you can pass an allocator in to use, but the allocator
// has to match the type of the one used by the underlying container
typedef long double T;
typedef std::greater<T> Comp;
typedef test_allocator<T> Alloc;
typedef std::deque<T, Alloc> Cont;

Cont c{2,3,0,1};
std::priority_queue<T, Cont, Comp> source(Comp(), c);
std::priority_queue pri(source, Alloc(2)); // queue(queue &, allocator)
static_assert(std::is_same_v<decltype(pri)::value_type, T>, "");
static_assert(std::is_same_v<decltype(pri)::container_type, Cont>, "");
assert(pri.size() == 4);
assert(pri.top() == 0);
typedef short T;
typedef std::greater<T> Comp;
typedef test_allocator<T> Alloc;
typedef std::deque<T, Alloc> Cont;
typedef test_allocator<int> ConvertibleToAlloc;
static_assert(std::uses_allocator_v<Cont, ConvertibleToAlloc> &&
!std::is_same_v<typename Cont::allocator_type, ConvertibleToAlloc>);

{
Comp comp;
Cont cont;
std::priority_queue pri(comp, cont, Alloc(2));
static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
}

{
Comp comp;
Cont cont;
std::priority_queue pri(comp, cont, ConvertibleToAlloc(2));
static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
}

{
Comp comp;
Cont cont;
std::priority_queue pri(comp, std::move(cont), Alloc(2));
static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
}

{
Comp comp;
Cont cont;
std::priority_queue pri(comp, std::move(cont), ConvertibleToAlloc(2));
static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
}
}

{
typedef short T;
typedef std::greater<T> Comp;
typedef test_allocator<T> Alloc;
typedef std::deque<T, Alloc> Cont;
typedef test_allocator<int> ConvertibleToAlloc;
static_assert(std::uses_allocator_v<Cont, ConvertibleToAlloc> &&
!std::is_same_v<typename Cont::allocator_type, ConvertibleToAlloc>);

{
std::priority_queue<T, Cont, Comp> source;
std::priority_queue pri(source, Alloc(2));
static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
}

{
std::priority_queue<T, Cont, Comp> source;
std::priority_queue pri(source, ConvertibleToAlloc(2));
static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
}

{
std::priority_queue<T, Cont, Comp> source;
std::priority_queue pri(std::move(source), Alloc(2));
static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
}

{
std::priority_queue<T, Cont, Comp> source;
std::priority_queue pri(std::move(source), ConvertibleToAlloc(2));
static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
}
}

return 0;
return 0;
}
Loading

0 comments on commit dd15c27

Please sign in to comment.