[libc++] [LWG2993] reference_wrapper<T> conversion from U&&

Implement the resolution of LWG2993. Replace a deleted constructor
with a constructor that SFINAEs away in appropriate circumstances.
Also, now that the constructor is templated, we must have an
explicit deduction guide to make CTAD work.

Some tests have been merged in from Agustín Bergé's D40259.

Differential Revision: https://reviews.llvm.org/D92725
This commit is contained in:
Arthur O'Dwyer 2020-12-05 19:37:41 -05:00
parent bd03f6df51
commit eec04092d6
8 changed files with 234 additions and 6 deletions

View File

@ -35,7 +35,7 @@
"`2981 <https://wg21.link/LWG2981>`__","Remove redundant deduction guides from standard library","Albuquerque","",""
"`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","",""
"`2993 <https://wg21.link/LWG2993>`__","reference_wrapper<T> conversion from T&&","Albuquerque","",""
"`2993 <https://wg21.link/LWG2993>`__","reference_wrapper<T> conversion from T&&","Albuquerque","|Complete|","13.0"
"`2998 <https://wg21.link/LWG2998>`__","Requirements on function objects passed to {``forward_``,}list-specific algorithms","Albuquerque","|Nothing To Do|",""
"`3001 <https://wg21.link/LWG3001>`__","weak_ptr::element_type needs remove_extent_t","Albuquerque","",""
"`3024 <https://wg21.link/LWG3024>`__","variant's copies must be deleted instead of disabled via SFINAE","Albuquerque","|Complete|",""

1 Issue # Issue Name Meeting Status First released version
35 `2981 <https://wg21.link/LWG2981>`__ Remove redundant deduction guides from standard library Albuquerque
36 `2982 <https://wg21.link/LWG2982>`__ Making size_type consistent in associative container deduction guides Albuquerque
37 `2988 <https://wg21.link/LWG2988>`__ Clause 32 cleanup missed one typename Albuquerque
38 `2993 <https://wg21.link/LWG2993>`__ reference_wrapper<T> conversion from T&& Albuquerque |Complete| 13.0
39 `2998 <https://wg21.link/LWG2998>`__ Requirements on function objects passed to {``forward_``,}list-specific algorithms Albuquerque |Nothing To Do|
40 `3001 <https://wg21.link/LWG3001>`__ weak_ptr::element_type needs remove_extent_t Albuquerque
41 `3024 <https://wg21.link/LWG3024>`__ variant's copies must be deleted instead of disabled via SFINAE Albuquerque |Complete|

View File

@ -380,13 +380,24 @@ public:
private:
type* __f_;
#ifndef _LIBCPP_CXX03_LANG
static void __fun(_Tp&) _NOEXCEPT;
static void __fun(_Tp&&) = delete;
#endif
public:
// construct/copy/destroy
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
#ifdef _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY
reference_wrapper(type& __f) _NOEXCEPT
: __f_(_VSTD::addressof(__f)) {}
#ifndef _LIBCPP_CXX03_LANG
private: reference_wrapper(type&&); public: // = delete; // do not bind to temps
#else
template <class _Up, class = _EnableIf<!__is_same_uncvref<_Up, reference_wrapper>::value, decltype(__fun(_VSTD::declval<_Up>())) >>
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
reference_wrapper(_Up&& __u) _NOEXCEPT_(noexcept(__fun(_VSTD::declval<_Up>()))) {
type& __f = static_cast<_Up&&>(__u);
__f_ = _VSTD::addressof(__f);
}
#endif
// access
@ -511,6 +522,10 @@ public:
#endif // _LIBCPP_CXX03_LANG
};
#ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES
template <class _Tp>
reference_wrapper(_Tp&) -> reference_wrapper<_Tp>;
#endif
template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17

View File

@ -42,8 +42,8 @@ public:
typedef see below result_type; // Not always defined
// construct/copy/destroy
reference_wrapper(T&) noexcept;
reference_wrapper(T&&) = delete; // do not bind to temps
template<class U>
reference_wrapper(U&&);
reference_wrapper(const reference_wrapper<T>& x) noexcept;
// assignment
@ -59,6 +59,9 @@ public:
operator() (ArgTypes&&...) const;
};
template <class T>
reference_wrapper(T&) -> reference_wrapper<T>;
template <class T> reference_wrapper<T> ref(T& t) noexcept;
template <class T> void ref(const T&& t) = delete;
template <class T> reference_wrapper<T> ref(reference_wrapper<T>t) noexcept;

View File

@ -21,6 +21,12 @@ class functor1
{
};
struct convertible_to_int_ref {
int val = 0;
operator int&() { return val; }
operator int const&() const { return val; }
};
template <class T>
void
test(T& t)
@ -56,5 +62,19 @@ int main(int, char**)
const int j = 0;
test(j);
#if TEST_STD_VER >= 11
convertible_to_int_ref convi;
test(convi);
convertible_to_int_ref const convic;
test(convic);
{
using Ref = std::reference_wrapper<int>;
static_assert((std::is_assignable<Ref&, int&>::value), "");
static_assert((!std::is_assignable<Ref&, int>::value), "");
static_assert((!std::is_assignable<Ref&, int&&>::value), "");
}
#endif
return 0;
}

View File

@ -0,0 +1,31 @@
//===----------------------------------------------------------------------===//
//
// 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
// UNSUPPORTED: libcpp-no-deduction-guides
// <functional>
// template <class T>
// reference_wrapper(T&) -> reference_wrapper<T>;
#include <functional>
int main()
{
int i = 0;
std::reference_wrapper ri(i);
static_assert(std::is_same_v<decltype(ri), std::reference_wrapper<int>>);
std::reference_wrapper ri2(ri);
static_assert(std::is_same_v<decltype(ri2), std::reference_wrapper<int>>);
const int j = 0;
std::reference_wrapper rj(j);
static_assert(std::is_same_v<decltype(rj), std::reference_wrapper<const int>>);
std::reference_wrapper rj2(rj);
static_assert(std::is_same_v<decltype(rj2), std::reference_wrapper<const int>>);
}

View File

@ -0,0 +1,81 @@
//===----------------------------------------------------------------------===//
//
// 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
// <functional>
//
// reference_wrapper
//
// template <class U>
// reference_wrapper(U&&) noexcept(see below);
#include <functional>
#include <cassert>
struct convertible_to_int_ref {
int val = 0;
operator int&() { return val; }
operator int const&() const { return val; }
};
template <bool IsNothrow>
struct nothrow_convertible {
int val = 0;
operator int&() noexcept(IsNothrow) { return val; }
};
struct convertible_from_int {
convertible_from_int(int) {}
};
void meow(std::reference_wrapper<int>) {}
void meow(convertible_from_int) {}
int gi;
std::reference_wrapper<int> purr() { return gi; };
template <class T>
void
test(T& t)
{
std::reference_wrapper<T> r(t);
assert(&r.get() == &t);
}
void f() {}
int main()
{
convertible_to_int_ref convi;
test(convi);
convertible_to_int_ref const convic;
test(convic);
{
using Ref = std::reference_wrapper<int>;
static_assert((std::is_nothrow_constructible<Ref, nothrow_convertible<true>>::value), "");
static_assert((!std::is_nothrow_constructible<Ref, nothrow_convertible<false>>::value), "");
}
{
meow(0);
(true) ? purr() : 0;
}
#ifdef __cpp_deduction_guides
{
int i = 0;
std::reference_wrapper ri(i);
static_assert((std::is_same<decltype(ri), std::reference_wrapper<int>>::value), "" );
const int j = 0;
std::reference_wrapper rj(j);
static_assert((std::is_same<decltype(rj), std::reference_wrapper<const int>>::value), "" );
}
#endif
}

View File

@ -0,0 +1,61 @@
//===----------------------------------------------------------------------===//
//
// 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
// <functional>
//
// reference_wrapper
//
// template <class U>
// reference_wrapper(U&&);
#include <functional>
#include <cassert>
struct B {} b;
struct A1 {
operator B& () const { return b; }
};
struct A2 {
operator B& () const noexcept { return b; }
};
int main()
{
{
std::reference_wrapper<B> b1 = A1();
assert(&b1.get() == &b);
b1 = A1();
assert(&b1.get() == &b);
static_assert(std::is_convertible<A1, std::reference_wrapper<B>>::value, "");
static_assert(!std::is_nothrow_constructible<std::reference_wrapper<B>, A1>::value, "");
#if TEST_STD_VER >= 20
static_assert(!std::is_nothrow_convertible_v<A1, std::reference_wrapper<B>>);
#endif
static_assert(std::is_assignable<std::reference_wrapper<B>, A1>::value, "");
static_assert(!std::is_nothrow_assignable<std::reference_wrapper<B>, A1>::value, "");
}
{
std::reference_wrapper<B> b2 = A2();
assert(&b2.get() == &b);
b2 = A2();
assert(&b2.get() == &b);
static_assert(std::is_convertible<A2, std::reference_wrapper<B>>::value, "");
static_assert(std::is_nothrow_constructible<std::reference_wrapper<B>, A2>::value, "");
#if TEST_STD_VER >= 20
static_assert(std::is_nothrow_convertible_v<A2, std::reference_wrapper<B>>);
#endif
static_assert(std::is_assignable<std::reference_wrapper<B>, A2>::value, "");
static_assert(std::is_nothrow_assignable<std::reference_wrapper<B>, A2>::value, "");
}
}

View File

@ -14,6 +14,7 @@
#include <functional>
#include <cassert>
#include <type_traits>
#include "test_macros.h"
@ -43,5 +44,21 @@ int main(int, char**)
const int j = 0;
test(j);
{
using Ref = std::reference_wrapper<int>;
static_assert((std::is_constructible<Ref, int&>::value), "");
static_assert((!std::is_constructible<Ref, int>::value), "");
static_assert((!std::is_constructible<Ref, int&&>::value), "");
}
#if TEST_STD_VER >= 11
{
using Ref = std::reference_wrapper<int>;
static_assert((std::is_nothrow_constructible<Ref, int&>::value), "");
static_assert((!std::is_nothrow_constructible<Ref, int>::value), "");
static_assert((!std::is_nothrow_constructible<Ref, int&&>::value), "");
}
#endif
return 0;
}