diff --git a/libcxx/include/__functional_base b/libcxx/include/__functional_base --- a/libcxx/include/__functional_base +++ b/libcxx/include/__functional_base @@ -380,12 +380,22 @@ private: type* __f_; +#ifndef _LIBCPP_CXX03_LANG + static void __fun(_Tp&) _NOEXCEPT; + static void __fun(_Tp&&) = delete; +#endif + public: // construct/copy/destroy +#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 reference_wrapper(_Up&& __u) _NOEXCEPT_(noexcept(__fun(_VSTD::declval<_Up>()))) { + type& __f = static_cast<_Up&&>(__u); + __f_ = _VSTD::addressof(__f); + } #endif // access @@ -508,6 +518,10 @@ #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 diff --git a/libcxx/include/functional b/libcxx/include/functional --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -42,8 +42,8 @@ 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 @@ 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; diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.assign/copy_assign.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.assign/copy_assign.pass.cpp --- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.assign/copy_assign.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.assign/copy_assign.pass.cpp @@ -21,6 +21,12 @@ { }; +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 @@ 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; } diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/deduct.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/deduct.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/deduct.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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<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, ""); +} diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_conv_ctor.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_conv_ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_conv_ctor.pass.cpp @@ -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 +} diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_conv_ctor2.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_conv_ctor2.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_conv_ctor2.pass.cpp @@ -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, ""); + } +} diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_ctor.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_ctor.pass.cpp --- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_ctor.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_ctor.pass.cpp @@ -14,6 +14,7 @@ #include <functional> #include <cassert> +#include <type_traits> #include "test_macros.h" @@ -43,5 +44,21 @@ 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; }