mirror of
https://github.com/intel/llvm.git
synced 2026-01-27 06:06:34 +08:00
[libc++] Implement LWG3528 (make_from_tuple can perform (the equivalent of) a C-style cast) (#85263)
Implement [LWG3528](https://wg21.link/LWG3528). Based on LWG3528(https://wg21.link/LWG3528) and http://eel.is/c++draft/description#structure.requirements-9, the standard allows to impose requirements, we constraint `std::make_from_tuple` to make `std::make_from_tuple` SFINAE friendly and also avoid worse diagnostic messages. We still keep the constraints of `std::__make_from_tuple_impl` so that `std::__make_from_tuple_impl` will have the same advantages when used alone. --------- Signed-off-by: yronglin <yronglin777@gmail.com>
This commit is contained in:
@@ -77,7 +77,7 @@
|
||||
`3523 <https://wg21.link/LWG3523>`__,"``iota_view::sentinel`` is not always ``iota_view``'s sentinel","June 2021","","","|ranges|"
|
||||
`3526 <https://wg21.link/LWG3526>`__,"Return types of ``uses_allocator_construction_args`` unspecified","June 2021","",""
|
||||
`3527 <https://wg21.link/LWG3527>`__,"``uses_allocator_construction_args`` handles rvalue pairs of rvalue references incorrectly","June 2021","",""
|
||||
`3528 <https://wg21.link/LWG3528>`__,"``make_from_tuple`` can perform (the equivalent of) a C-style cast","June 2021","",""
|
||||
`3528 <https://wg21.link/LWG3528>`__,"``make_from_tuple`` can perform (the equivalent of) a C-style cast","June 2021","|Complete|","19.0"
|
||||
`3529 <https://wg21.link/LWG3529>`__,"``priority_queue(first, last)`` should construct ``c`` with ``(first, last)``","June 2021","|Complete|","14.0"
|
||||
`3530 <https://wg21.link/LWG3530>`__,"``BUILTIN-PTR-MEOW`` should not opt the type out of syntactic checks","June 2021","",""
|
||||
`3532 <https://wg21.link/LWG3532>`__,"``split_view<V, P>::inner-iterator<true>::operator++(int)`` should depend on ``Base``","June 2021","","","|ranges|"
|
||||
|
||||
|
@@ -1377,15 +1377,41 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) apply(_Fn&& __f, _Tuple&&
|
||||
std::forward<_Tuple>(__t),
|
||||
typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type{}))
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
template <class _Tp, class _Tuple, size_t... _Idx>
|
||||
inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>)
|
||||
noexcept(noexcept(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...)))
|
||||
requires is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...> {
|
||||
return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...);
|
||||
}
|
||||
#else
|
||||
template <class _Tp, class _Tuple, size_t... _Idx>
|
||||
inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>,
|
||||
enable_if_t<is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>> * = nullptr)
|
||||
_LIBCPP_NOEXCEPT_RETURN(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...))
|
||||
#endif // _LIBCPP_STD_VER >= 20
|
||||
|
||||
template <class _Tp, class _Tuple,
|
||||
class _Seq = typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type, class = void>
|
||||
inline constexpr bool __can_make_from_tuple = false;
|
||||
|
||||
template <class _Tp, class _Tuple, size_t... _Idx>
|
||||
inline constexpr bool __can_make_from_tuple<_Tp, _Tuple, __tuple_indices<_Idx...>,
|
||||
enable_if_t<is_constructible_v<_Tp, decltype(std::get<_Idx>(std::declval<_Tuple>()))...>>> = true;
|
||||
|
||||
// Based on LWG3528(https://wg21.link/LWG3528) and http://eel.is/c++draft/description#structure.requirements-9,
|
||||
// the standard allows to impose requirements, we constraint std::make_from_tuple to make std::make_from_tuple
|
||||
// SFINAE friendly and also avoid worse diagnostic messages. We still keep the constraints of std::__make_from_tuple_impl
|
||||
// so that std::__make_from_tuple_impl will have the same advantages when used alone.
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
template <class _Tp, class _Tuple>
|
||||
requires __can_make_from_tuple<_Tp, _Tuple> // strengthen
|
||||
#else
|
||||
template <class _Tp, class _Tuple, class = enable_if_t<__can_make_from_tuple<_Tp, _Tuple>>> // strengthen
|
||||
#endif // _LIBCPP_STD_VER >= 20
|
||||
inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp make_from_tuple(_Tuple&& __t)
|
||||
_LIBCPP_NOEXCEPT_RETURN(std::__make_from_tuple_impl<_Tp>(
|
||||
std::forward<_Tuple>(__t), typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type{}))
|
||||
|
||||
# undef _LIBCPP_NOEXCEPT_RETURN
|
||||
|
||||
# endif // _LIBCPP_STD_VER >= 17
|
||||
|
||||
@@ -195,6 +195,94 @@ void test_noexcept() {
|
||||
}
|
||||
}
|
||||
|
||||
namespace LWG3528 {
|
||||
template <class T, class Tuple>
|
||||
auto test_make_from_tuple(T&&, Tuple&& t) -> decltype(std::make_from_tuple<T>(t), uint8_t()) {
|
||||
return 0;
|
||||
}
|
||||
template <class T, class Tuple>
|
||||
uint32_t test_make_from_tuple(...) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T, class Tuple>
|
||||
static constexpr bool can_make_from_tuple =
|
||||
std::is_same_v<decltype(test_make_from_tuple<T, Tuple>(T{}, Tuple{})), uint8_t>;
|
||||
|
||||
template <class T, class Tuple>
|
||||
auto test_make_from_tuple_impl(T&&, Tuple&& t)
|
||||
-> decltype(std::__make_from_tuple_impl<T>(
|
||||
t, typename std::__make_tuple_indices< std::tuple_size_v<std::remove_reference_t<Tuple>>>::type{}),
|
||||
uint8_t()) {
|
||||
return 0;
|
||||
}
|
||||
template <class T, class Tuple>
|
||||
uint32_t test_make_from_tuple_impl(...) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T, class Tuple>
|
||||
static constexpr bool can_make_from_tuple_impl =
|
||||
std::is_same_v<decltype(test_make_from_tuple_impl<T, Tuple>(T{}, Tuple{})), uint8_t>;
|
||||
|
||||
struct A {
|
||||
int a;
|
||||
};
|
||||
struct B : public A {};
|
||||
|
||||
struct C {
|
||||
C(const B&) {}
|
||||
};
|
||||
|
||||
enum class D {
|
||||
ONE,
|
||||
TWO,
|
||||
};
|
||||
|
||||
// Test std::make_from_tuple constraints.
|
||||
|
||||
// reinterpret_cast
|
||||
static_assert(!can_make_from_tuple<int*, std::tuple<A*>>);
|
||||
static_assert(can_make_from_tuple<A*, std::tuple<A*>>);
|
||||
|
||||
// const_cast
|
||||
static_assert(!can_make_from_tuple<char*, std::tuple<const char*>>);
|
||||
static_assert(!can_make_from_tuple<volatile char*, std::tuple<const volatile char*>>);
|
||||
static_assert(can_make_from_tuple<volatile char*, std::tuple<volatile char*>>);
|
||||
static_assert(can_make_from_tuple<char*, std::tuple<char*>>);
|
||||
static_assert(can_make_from_tuple<const char*, std::tuple<char*>>);
|
||||
static_assert(can_make_from_tuple<const volatile char*, std::tuple<volatile char*>>);
|
||||
|
||||
// static_cast
|
||||
static_assert(!can_make_from_tuple<int, std::tuple<D>>);
|
||||
static_assert(!can_make_from_tuple<D, std::tuple<int>>);
|
||||
static_assert(can_make_from_tuple<long, std::tuple<int>>);
|
||||
static_assert(can_make_from_tuple<double, std::tuple<float>>);
|
||||
static_assert(can_make_from_tuple<float, std::tuple<double>>);
|
||||
|
||||
// Test std::__make_from_tuple_impl constraints.
|
||||
|
||||
// reinterpret_cast
|
||||
static_assert(!can_make_from_tuple_impl<int*, std::tuple<A*>>);
|
||||
static_assert(can_make_from_tuple_impl<A*, std::tuple<A*>>);
|
||||
|
||||
// const_cast
|
||||
static_assert(!can_make_from_tuple_impl<char*, std::tuple<const char*>>);
|
||||
static_assert(!can_make_from_tuple_impl<volatile char*, std::tuple<const volatile char*>>);
|
||||
static_assert(can_make_from_tuple_impl<volatile char*, std::tuple<volatile char*>>);
|
||||
static_assert(can_make_from_tuple_impl<char*, std::tuple<char*>>);
|
||||
static_assert(can_make_from_tuple_impl<const char*, std::tuple<char*>>);
|
||||
static_assert(can_make_from_tuple_impl<const volatile char*, std::tuple<volatile char*>>);
|
||||
|
||||
// static_cast
|
||||
static_assert(!can_make_from_tuple_impl<int, std::tuple<D>>);
|
||||
static_assert(!can_make_from_tuple_impl<D, std::tuple<int>>);
|
||||
static_assert(can_make_from_tuple_impl<long, std::tuple<int>>);
|
||||
static_assert(can_make_from_tuple_impl<double, std::tuple<float>>);
|
||||
static_assert(can_make_from_tuple_impl<float, std::tuple<double>>);
|
||||
|
||||
} // namespace LWG3528
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test_constexpr_construction();
|
||||
|
||||
Reference in New Issue
Block a user