[libc++] P0433R2: add the remaining deduction guides.

Add deduction guides to `valarray` and `scoped_allocator_adaptor`. This largely
finishes implementation of the paper:

* deduction guides for other classes mentioned in the paper were
  implemented previously (see the list below);
* deduction guides for several classes contained in the proposal
  (`reference_wrapper`, `lock_guard`, `scoped_lock`, `unique_lock`,
  `shared_lock`) were removed by [LWG2981](https://wg21.link/LWG2981).

Also add deduction guides to the synopsis for the few classes (e.g. `pair`)
where they were missing.

The only part of the paper that isn't fully implemented after this patch is
making sure certain deduction guides don't participate in overload resolution
when given incorrect template parameters.

List of significant commits implementing the other parts of P0433 (omitting some
minor fixes):

* [pair](af65856eec)
* [basic_string](6d9f750dec)
* [array](0ca8c0895c)
* [deque](dbb6f8a817)
* [forward_list](e076700b77)
* [list](4a227e582b)
* [vector](df8f754792)
* [queue/stack/priority_queue](5b8b8b5dce)
* [basic_regex](edd5e29cfe)
* [optional](f35b4bc395)
* [map/multimap](edfe8525de)
* [set/multiset](e20865c387)
* [unordered_set/unordered_multiset](296a80102a)
* [unordered_map/unordered_multimap](dfcd4384cb)
* [function](e1eabcdfad)
* [tuple](1308011e1b)
* [shared_ptr/weak_ptr](83564056d4)

Additional notes:
* It was revision 2 of the paper that was voted into the Standard.
  P0433R3 is a separate paper that is not part of the Standard.
* The paper also mandates removing several `make_*_searcher` functions
  (e.g. `make_boyer_moore_searcher`) which are currently not implemented
  (except in `experimental/`).
* The `__cpp_lib_deduction_guides` feature test macro from the paper was
  accidentally omitted from the Standard.

Differential Revision: https://reviews.llvm.org/D112510
This commit is contained in:
Konstantin Varlamov 2021-10-28 00:36:19 -07:00
parent c9174f63b6
commit f9f97cae82
10 changed files with 191 additions and 8 deletions

View File

@ -40,7 +40,7 @@ Paper Status
.. note::
.. [#note-P0433] P0433: So far, only the ``<string>``, sequence containers, container adaptors and ``<regex>`` portions of P0433 have been implemented.
.. [#note-P0433] P0433: The only part not fully implemented is the requirement that certain deduction guides should not participate in overload resolution when given incorrect template arguments.
.. [#note-P0607] P0607: The parts of P0607 that are not done are the ``<regex>`` bits.

View File

@ -32,7 +32,7 @@
"`2978 <https://wg21.link/LWG2978>`__","Hash support for pmr::string and friends","Albuquerque","",""
"`2979 <https://wg21.link/LWG2979>`__","aligned_union should require complete object types","Albuquerque","|Complete|",""
"`2980 <https://wg21.link/LWG2980>`__","Cannot compare_exchange empty pointers","Albuquerque","",""
"`2981 <https://wg21.link/LWG2981>`__","Remove redundant deduction guides from standard library","Albuquerque","",""
"`2981 <https://wg21.link/LWG2981>`__","Remove redundant deduction guides from standard library","Albuquerque","|Nothing To Do|",""
"`2982 <https://wg21.link/LWG2982>`__","Making size_type consistent in associative container deduction guides","Albuquerque","",""
"`2988 <https://wg21.link/LWG2988>`__","Clause 32 cleanup missed one typename","Albuquerque","|Complete|","13.0"
"`2993 <https://wg21.link/LWG2993>`__","reference_wrapper<T> conversion from T&&","Albuquerque","|Complete|","13.0"

Can't render this file because it has a wrong number of fields in line 2.

View File

@ -91,6 +91,10 @@ public:
scoped_allocator_adaptor select_on_container_copy_construction() const noexcept;
};
template<class OuterAlloc, class... InnerAllocs>
scoped_allocator_adaptor(OuterAlloc, InnerAllocs...)
-> scoped_allocator_adaptor<OuterAlloc, InnerAllocs...>;
template <class OuterA1, class OuterA2, class... InnerAllocs>
bool
operator==(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a,
@ -649,6 +653,12 @@ private:
template <class...> friend class __scoped_allocator_storage;
};
#if _LIBCPP_STD_VER > 14
template<class _OuterAlloc, class... _InnerAllocs>
scoped_allocator_adaptor(_OuterAlloc, _InnerAllocs...)
-> scoped_allocator_adaptor<_OuterAlloc, _InnerAllocs...>;
#endif
template <class _OuterA1, class _OuterA2>
inline _LIBCPP_INLINE_VISIBILITY
bool

View File

@ -95,6 +95,8 @@ struct pair
is_nothrow_swappable_v<T2>); // constexpr in C++20
};
template<class T1, class T2> pair(T1, T2) -> pair<T1, T2>;
template <class T1, class T2> bool operator==(const pair<T1,T2>&, const pair<T1,T2>&); // constexpr in C++14
template <class T1, class T2> bool operator!=(const pair<T1,T2>&, const pair<T1,T2>&); // constexpr in C++14, removed in C++20
template <class T1, class T2> bool operator< (const pair<T1,T2>&, const pair<T1,T2>&); // constexpr in C++14, removed in C++20

View File

@ -105,6 +105,8 @@ public:
void resize(size_t n, value_type x = value_type());
};
template<class T, size_t cnt> valarray(const T(&)[cnt], size_t) -> valarray<T>;
class slice
{
public:
@ -1081,6 +1083,11 @@ private:
valarray& __assign_range(const value_type* __f, const value_type* __l);
};
#if _LIBCPP_STD_VER > 14
template<class _Tp, size_t _Size>
valarray(const _Tp(&)[_Size], size_t) -> valarray<_Tp>;
#endif
_LIBCPP_EXTERN_TEMPLATE(_LIBCPP_FUNC_VIS void valarray<size_t>::resize(size_t, size_t))
template <class _Op, class _Tp>

View File

@ -0,0 +1,73 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// <valarray>
// template<class T, size_t cnt> valarray(const T(&)[cnt], size_t) -> valarray<T>;
#include <valarray>
#include "test_macros.h"
int main(int, char**)
{
{
// From (initializer_list<T>)
std::valarray v = {1, 2, 3, 4, 5};
ASSERT_SAME_TYPE(decltype(v), std::valarray<int>);
}
{
// From (const T(&)[N], size_t)
long a[] = {1, 2, 3, 4, 5};
std::valarray v(a, 5);
ASSERT_SAME_TYPE(decltype(v), std::valarray<long>);
}
{
// From (const T&, size_t)
long a[] = {1, 2, 3, 4, 5};
std::valarray v(&a[0], 5);
// Surprising but true.
ASSERT_SAME_TYPE(decltype(v), std::valarray<long*>);
}
{
// From (slice_array<T>)
std::valarray<long> v{1,2,3,4,5};
std::valarray v2 = v[std::slice(2,3,1)];
static_assert(std::is_same_v<decltype(v2), std::valarray<long>>);
}
{
// From (gslice_array<T>)
std::valarray<long> v{1,2,3,4,5};
std::valarray v2 = v[std::gslice(0, {5}, {1})];
static_assert(std::is_same_v<decltype(v2), std::valarray<long>>);
}
{
// From (mask_array<T>)
std::valarray<long> v = {1, 2, 3, 4, 5};
std::valarray<bool> m = {true, false, true, false, true};
std::valarray v2 = v[m];
static_assert(std::is_same_v<decltype(v2), std::valarray<long>>);
}
{
// From (indirect_array<T>)
std::valarray<long> v = {1, 2, 3, 4, 5};
std::valarray<size_t> i = {1, 2, 3};
std::valarray v2 = v[i];
static_assert(std::is_same_v<decltype(v2), std::valarray<long>>);
}
return 0;
}

View File

@ -28,7 +28,7 @@
#include "test_macros.h"
class NotAnItertor {};
class NotAnIterator {};
template <typename T>
struct NotAnAllocator { typedef T value_type; };
@ -36,7 +36,7 @@ struct NotAnAllocator { typedef T value_type; };
int main(int, char**)
{
{ // Not an iterator at all
std::basic_string s1{NotAnItertor{}, NotAnItertor{}, std::allocator<char>{}}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'basic_string'}}
std::basic_string s1{NotAnIterator{}, NotAnIterator{}, std::allocator<char>{}}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'basic_string'}}
}
{ // Not an input iterator
std::basic_string<char16_t> s0;

View File

@ -8,7 +8,7 @@
// UNSUPPORTED: c++03
// <memory>
// <scoped_allocator>
// template <class OuterAlloc, class... InnerAllocs>
// class scoped_allocator_adaptor

View File

@ -0,0 +1,64 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// <scoped_allocator>
// template<class _OuterAlloc, class... _InnerAllocs>
// scoped_allocator_adaptor(_OuterAlloc, _InnerAllocs...)
// -> scoped_allocator_adaptor<_OuterAlloc, _InnerAllocs...>;
#include <scoped_allocator>
#include "test_macros.h"
#include "allocators.h"
int main(int, char**)
{
// Deduct from (const OuterAlloc&).
{
typedef A1<int> OuterAlloc;
OuterAlloc outer(3);
std::scoped_allocator_adaptor a(outer);
ASSERT_SAME_TYPE(decltype(a), std::scoped_allocator_adaptor<OuterAlloc>);
}
// Deduct from (OuterAlloc&&).
{
typedef A1<int> OuterAlloc;
std::scoped_allocator_adaptor a(OuterAlloc(3));
ASSERT_SAME_TYPE(decltype(a), std::scoped_allocator_adaptor<OuterAlloc>);
}
// Deduct from (const OuterAlloc&, const InnerAlloc&).
{
typedef A1<int> OuterAlloc;
typedef A2<int> InnerAlloc;
OuterAlloc outer(3);
InnerAlloc inner(4);
std::scoped_allocator_adaptor a(outer, inner);
ASSERT_SAME_TYPE(decltype(a), std::scoped_allocator_adaptor<OuterAlloc, InnerAlloc>);
}
// Deduct from (const OuterAlloc&, const InnerAlloc1&, InnerAlloc2&&).
{
typedef A1<int> OuterAlloc;
typedef A2<int> InnerAlloc1;
typedef A2<float> InnerAlloc2;
OuterAlloc outer(3);
InnerAlloc1 inner(4);
std::scoped_allocator_adaptor a(outer, inner, InnerAlloc2(5));
ASSERT_SAME_TYPE(
decltype(a), std::scoped_allocator_adaptor<OuterAlloc, InnerAlloc1, InnerAlloc2>);
}
return 0;
}

View File

@ -25,7 +25,7 @@ int main(int, char**)
{
// optional(T)
std::optional opt(5);
static_assert(std::is_same_v<decltype(opt), std::optional<int>>, "");
ASSERT_SAME_TYPE(decltype(opt), std::optional<int>);
assert(static_cast<bool>(opt));
assert(*opt == 5);
}
@ -33,16 +33,43 @@ int main(int, char**)
{
// optional(T)
std::optional opt(A{});
static_assert(std::is_same_v<decltype(opt), std::optional<A>>, "");
ASSERT_SAME_TYPE(decltype(opt), std::optional<A>);
assert(static_cast<bool>(opt));
}
{
// optional(const T&);
const int& source = 5;
std::optional opt(source);
ASSERT_SAME_TYPE(decltype(opt), std::optional<int>);
assert(static_cast<bool>(opt));
assert(*opt == 5);
}
{
// optional(T*);
const int* source = nullptr;
std::optional opt(source);
ASSERT_SAME_TYPE(decltype(opt), std::optional<const int*>);
assert(static_cast<bool>(opt));
assert(*opt == nullptr);
}
{
// optional(T[]);
int source[] = {1, 2, 3};
std::optional opt(source);
ASSERT_SAME_TYPE(decltype(opt), std::optional<int*>);
assert(static_cast<bool>(opt));
assert((*opt)[0] == 1);
}
// Test the implicit deduction guides
{
// optional(optional);
std::optional<char> source('A');
std::optional opt(source);
static_assert(std::is_same_v<decltype(opt), std::optional<char>>, "");
ASSERT_SAME_TYPE(decltype(opt), std::optional<char>);
assert(static_cast<bool>(opt) == static_cast<bool>(source));
assert(*opt == *source);
}