diff --git a/stl/inc/tuple b/stl/inc/tuple index c49a9205c5f..66edcc20877 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -1079,24 +1079,27 @@ constexpr decltype(auto) apply(_Callable&& _Obj, _Tuple&& _Tpl) noexcept( make_index_sequence>>{}); } -#if _HAS_CXX23 -template -#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv +template >>> +inline constexpr bool _Can_make_from_tuple = false; +template +inline constexpr bool _Can_make_from_tuple<_Ty, _Tuple, index_sequence<_Indices...>> = + is_constructible_v<_Ty, decltype(_STD get<_Indices>(_STD declval<_Tuple>()))...>; + template -#endif // ^^^ !_HAS_CXX23 ^^^ constexpr _Ty _Make_from_tuple_impl(_Tuple&& _Tpl, index_sequence<_Indices...>) noexcept( is_nothrow_constructible_v<_Ty, decltype(_STD get<_Indices>(_STD forward<_Tuple>(_Tpl)))...>) { - // construct _Ty from the elements of _Tpl - static_assert(is_constructible_v<_Ty, decltype(_STD get<_Indices>(_STD forward<_Tuple>(_Tpl)))...>, - "the target type must be constructible from the fields of the argument tuple (N4950 [tuple.apply]/4)."); return _Ty(_STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...); } #if _HAS_CXX23 _EXPORT_STD template -#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv + requires _Can_make_from_tuple<_Ty, _Tuple> +#elif _HAS_CXX20 _EXPORT_STD template -#endif // ^^^ !_HAS_CXX23 ^^^ + requires _Can_make_from_tuple<_Ty, _Tuple> +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +template , int> = 0> +#endif // ^^^ !_HAS_CXX20 ^^^ _NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) noexcept(noexcept(_STD _Make_from_tuple_impl<_Ty>( _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}))) /* strengthened */ { // construct _Ty from the elements of _Tpl diff --git a/tests/std/test.lst b/tests/std/test.lst index f854b835230..39dfd7cafe5 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -249,6 +249,7 @@ tests\LWG3146_excessive_unwrapping_ref_cref tests\LWG3234_math_special_overloads tests\LWG3422_seed_seq_ctors tests\LWG3480_directory_iterator_range +tests\LWG3528_make_from_tuple_impl tests\LWG3545_pointer_traits_sfinae tests\LWG3561_discard_block_engine_counter tests\LWG3610_iota_view_size_and_integer_class diff --git a/tests/std/tests/LWG3528_make_from_tuple_impl/env.lst b/tests/std/tests/LWG3528_make_from_tuple_impl/env.lst new file mode 100644 index 00000000000..2de7aab2959 --- /dev/null +++ b/tests/std/tests/LWG3528_make_from_tuple_impl/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_17_matrix.lst diff --git a/tests/std/tests/LWG3528_make_from_tuple_impl/test.compile.pass.cpp b/tests/std/tests/LWG3528_make_from_tuple_impl/test.compile.pass.cpp new file mode 100644 index 00000000000..0ca11479715 --- /dev/null +++ b/tests/std/tests/LWG3528_make_from_tuple_impl/test.compile.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +//===----------------------------------------------------------------------===// + +// derived from libc++'s test files: +// * std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp + +#include +#include +#include +#include + +struct A { + int a; +}; + +enum class D { + one, + two, +}; + +template +inline constexpr bool has_make_from_tuple = false; + +template +inline constexpr bool + has_make_from_tuple(std::declval()))>> = true; + +// Test std::make_from_tuple. + +// reinterpret_cast, std::tuple +static_assert(!has_make_from_tuple>); +static_assert(has_make_from_tuple>); + +// reinterpret_cast, std::array +static_assert(!has_make_from_tuple>); +static_assert(has_make_from_tuple>); + +// const_cast, std::tuple +static_assert(!has_make_from_tuple>); +static_assert(!has_make_from_tuple>); +static_assert(has_make_from_tuple>); +static_assert(has_make_from_tuple>); +static_assert(has_make_from_tuple>); +static_assert(has_make_from_tuple>); + +// const_cast, std::array +static_assert(!has_make_from_tuple>); +static_assert(!has_make_from_tuple>); +static_assert(has_make_from_tuple>); +static_assert(has_make_from_tuple>); +static_assert(has_make_from_tuple>); +static_assert(has_make_from_tuple>); + +// static_cast, std::tuple +static_assert(!has_make_from_tuple>); +static_assert(!has_make_from_tuple>); +static_assert(has_make_from_tuple>); +static_assert(has_make_from_tuple>); +static_assert(has_make_from_tuple>); + +// static_cast, std::array +static_assert(!has_make_from_tuple>); +static_assert(!has_make_from_tuple>); +static_assert(has_make_from_tuple>); +static_assert(has_make_from_tuple>); +static_assert(has_make_from_tuple>);