Skip to content

Commit

Permalink
[libc++] P0433R2: add the remaining deduction guides.
Browse files Browse the repository at this point in the history
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](af65856)
* [basic_string](6d9f750)
* [array](0ca8c08)
* [deque](dbb6f8a)
* [forward_list](e076700)
* [list](4a227e5)
* [vector](df8f754)
* [queue/stack/priority_queue](5b8b8b5)
* [basic_regex](edd5e29)
* [optional](f35b4bc)
* [map/multimap](edfe852)
* [set/multiset](e20865c)
* [unordered_set/unordered_multiset](296a801)
* [unordered_map/unordered_multimap](dfcd438)
* [function](e1eabcd)
* [tuple](1308011)
* [shared_ptr/weak_ptr](8356405)

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
  • Loading branch information
var-const committed Oct 28, 2021
1 parent c9174f6 commit f9f97ca
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 8 deletions.
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx17.rst
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx20Issues.csv
Expand Up @@ -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"
Expand Down
10 changes: 10 additions & 0 deletions libcxx/include/scoped_allocator
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions libcxx/include/utility
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions libcxx/include/valarray
Expand Up @@ -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:
Expand Down Expand Up @@ -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>
Expand Down
@@ -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;
}
Expand Up @@ -28,15 +28,15 @@

#include "test_macros.h"

class NotAnItertor {};
class NotAnIterator {};

template <typename T>
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;
Expand Down
Expand Up @@ -8,7 +8,7 @@

// UNSUPPORTED: c++03

// <memory>
// <scoped_allocator>

// template <class OuterAlloc, class... InnerAllocs>
// class scoped_allocator_adaptor
Expand Down
@@ -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;
}
Expand Up @@ -25,24 +25,51 @@ 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);
}

{
// 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);
}
Expand Down

0 comments on commit f9f97ca

Please sign in to comment.