diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h index 1f596a87f7cc7..4e66bd4e1d553 100644 --- a/libcxx/include/__utility/pair.h +++ b/libcxx/include/__utility/pair.h @@ -49,6 +49,33 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +#ifndef _LIBCPP_CXX03_LANG + +template +struct __check_pair_construction { + template + static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_implicit_default() { + return __is_implicitly_default_constructible<_T1>::value && __is_implicitly_default_constructible<_T2>::value; + } + + template + static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_default() { + return is_default_constructible<_T1>::value && is_default_constructible<_T2>::value; + } + + template + static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_pair_constructible() { + return is_constructible<_T1, _U1>::value && is_constructible<_T2, _U2>::value; + } + + template + static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_implicit() { + return is_convertible<_U1, _T1>::value && is_convertible<_U2, _T2>::value; + } +}; + +#endif + template struct __non_trivially_copyable_base { _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI __non_trivially_copyable_base() _NOEXCEPT {} @@ -104,40 +131,16 @@ struct _LIBCPP_TEMPLATE_VIS pair return *this; } #else - struct _CheckArgs { - template - static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_implicit_default() { - return __is_implicitly_default_constructible<_T1>::value && __is_implicitly_default_constructible<_T2>::value; - } - - template - static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_default() { - return is_default_constructible<_T1>::value && is_default_constructible<_T2>::value; - } - - template - static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_pair_constructible() { - return is_constructible::value && is_constructible::value; - } - - template - static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_implicit() { - return is_convertible<_U1, first_type>::value && is_convertible<_U2, second_type>::value; - } - }; - - template - using _CheckArgsDep _LIBCPP_NODEBUG = __conditional_t<_MaybeEnable, _CheckArgs, void>; - - template ::__enable_default(), int> = 0> - explicit(!_CheckArgsDep<_Dummy>::__enable_implicit_default()) _LIBCPP_HIDE_FROM_ABI constexpr pair() noexcept( + template , + __enable_if_t<_CheckArgsDep::__enable_default(), int> = 0> + explicit(!_CheckArgsDep::__enable_implicit_default()) _LIBCPP_HIDE_FROM_ABI constexpr pair() noexcept( is_nothrow_default_constructible::value && is_nothrow_default_constructible::value) : first(), second() {} - template ::template __is_pair_constructible<_T1 const&, _T2 const&>(), int> = 0> + template , + __enable_if_t<_CheckArgsDep::template __is_pair_constructible<_T1 const&, _T2 const&>(), int> = 0> _LIBCPP_HIDE_FROM_ABI - _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgsDep<_Dummy>::template __is_implicit<_T1 const&, _T2 const&>()) + _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgsDep::template __is_implicit<_T1 const&, _T2 const&>()) pair(_T1 const& __t1, _T2 const& __t2) noexcept(is_nothrow_copy_constructible::value && is_nothrow_copy_constructible::value) : first(__t1), second(__t2) {} @@ -150,41 +153,52 @@ struct _LIBCPP_TEMPLATE_VIS pair class _U1, class _U2, # endif - __enable_if_t<_CheckArgs::template __is_pair_constructible<_U1, _U2>(), int> = 0 > - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>()) + __enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1, _U2>(), int> = 0 > + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1, _U2>()) pair(_U1&& __u1, _U2&& __u2) noexcept(is_nothrow_constructible::value && is_nothrow_constructible::value) : first(std::forward<_U1>(__u1)), second(std::forward<_U2>(__u2)) { } # if _LIBCPP_STD_VER >= 23 - template (), int> = 0> - _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_CheckArgs::template __is_implicit<_U1&, _U2&>()) + template ::template __is_pair_constructible<_U1&, _U2&>(), int> = 0> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&, _U2&>()) pair(pair<_U1, _U2>& __p) noexcept((is_nothrow_constructible::value && is_nothrow_constructible::value)) : first(__p.first), second(__p.second) {} # endif - template (), int> = 0> - _LIBCPP_HIDE_FROM_ABI - _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1 const&, _U2 const&>()) + template < + class _U1, + class _U2, + __enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1 const&, _U2 const&>(), + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit( + !__check_pair_construction<_T1, _T2>::template __is_implicit<_U1 const&, _U2 const&>()) pair(pair<_U1, _U2> const& __p) noexcept(is_nothrow_constructible::value && is_nothrow_constructible::value) : first(__p.first), second(__p.second) {} - template (), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>()) + template ::template __is_pair_constructible<_U1, _U2>(), int> = 0> + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1, _U2>()) pair(pair<_U1, _U2>&& __p) noexcept(is_nothrow_constructible::value && is_nothrow_constructible::value) : first(std::forward<_U1>(__p.first)), second(std::forward<_U2>(__p.second)) {} # if _LIBCPP_STD_VER >= 23 - template (), int> = 0> - _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_CheckArgs::template __is_implicit()) + template < + class _U1, + class _U2, + __enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible(), + int> = 0> + _LIBCPP_HIDE_FROM_ABI constexpr explicit( + !__check_pair_construction<_T1, _T2>::template __is_implicit()) pair(const pair<_U1, _U2>&& __p) noexcept(is_nothrow_constructible::value && is_nothrow_constructible::value) : first(std::move(__p.first)), second(std::move(__p.second)) {} diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/explicit_deduction_guides.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/explicit_deduction_guides.pass.cpp new file mode 100644 index 0000000000000..d580e04012706 --- /dev/null +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/explicit_deduction_guides.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++17 + +// + +// template +// pair(T1, T2) -> pair; + +// Test that the explicit deduction guide for std::pair correctly decays function lvalues and +// behaves different from std::make_pair. + +#include +#include +#include +#include + +#include "test_macros.h" + +void dummy() {} + +constexpr void test_decay() { + char arr[1]{}; + std::pair pr(arr, dummy); + + ASSERT_SAME_TYPE(decltype(pr), std::pair); + + assert(pr == std::make_pair(arr, dummy)); +} + +TEST_CONSTEXPR_CXX20 void test_unwrap() { + int n = 0; + std::pair pr(std::ref(n), dummy); + + ASSERT_SAME_TYPE(decltype(pr), std::pair, void (*)()>); + static_assert(!std::is_same_v); + + assert(&(pr.first.get()) == &n); + assert(pr.second == dummy); +} + +constexpr bool test() { + test_decay(); + if (TEST_STD_AT_LEAST_20_OR_RUNTIME_EVALUATED) + test_unwrap(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +}