[PATCH] libstdc++: Implement LWG3528 make_from_tuple can perform (the equivalent of) a C-style cast
Tomasz Kaminski
tkaminsk@redhat.com
Tue Jun 10 12:55:36 GMT 2025
On Mon, Jun 9, 2025 at 4:07 PM Jonathan Wakely <jwakely@redhat.com> wrote:
> From: Yihan Wang <yronglin777@gmail.com>
>
> Implement LWG3528 to make std::make_from_tuple SFINAE friendly.
>
> libstdc++-v3/ChangeLog:
>
> * include/std/tuple (__can_make_from_tuple): New variable
> template.
> (__make_from_tuple_impl): Add static_assert.
> (make_from_tuple): Constrain using __can_make_from_tuple.
> * testsuite/20_util/tuple/dr3528.cc: New test.
>
> Signed-off-by: Yihan Wang <yronglin777@gmail.com>
> Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
> ---
>
> Here's a simpler version of Yihan's patch, with constraints on
> std::make_from_tuple but not on __make_from_tuple_impl, and with an
> original test rather than one copied from MSVC and libc++.
>
> Lightly tested on x86_64-linux, full testing underway.
>
LGTM. Thanks.
>
> libstdc++-v3/include/std/tuple | 24 +++++++++-
> .../testsuite/20_util/tuple/dr3528.cc | 44 +++++++++++++++++++
> 2 files changed, 66 insertions(+), 2 deletions(-)
> create mode 100644 libstdc++-v3/testsuite/20_util/tuple/dr3528.cc
>
> diff --git a/libstdc++-v3/include/std/tuple
> b/libstdc++-v3/include/std/tuple
> index 2e69af13a98b..b39ce710984c 100644
> --- a/libstdc++-v3/include/std/tuple
> +++ b/libstdc++-v3/include/std/tuple
> @@ -2939,19 +2939,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> #endif
>
> #ifdef __cpp_lib_make_from_tuple // C++ >= 17
> + template <typename _Tp, typename _Tuple, typename _Seq
> + =
> make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>>
> + constexpr bool __can_make_from_tuple = false;
> +
> + // _GLIBCXX_RESOLVE_LIB_DEFECTS
> + // 3528. make_from_tuple can perform (the equivalent of) a C-style cast
> + template <typename _Tp, typename _Tuple, size_t... _Idx>
> + constexpr bool __can_make_from_tuple<_Tp, _Tuple,
> index_sequence<_Idx...>>
> + = is_constructible_v<_Tp,
> +
> decltype(std::get<_Idx>(std::declval<_Tuple>()))...>;
> +
> template <typename _Tp, typename _Tuple, size_t... _Idx>
> constexpr _Tp
> __make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>)
> - { return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); }
> + {
> + static_assert(__can_make_from_tuple<_Tp, _Tuple,
> index_sequence<_Idx...>>);
> + return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...);
> + }
>
> #if __cpp_lib_tuple_like // >= C++23
> template <typename _Tp, __tuple_like _Tuple>
> #else
> template <typename _Tp, typename _Tuple>
> #endif
> - constexpr _Tp
> + constexpr auto
> make_from_tuple(_Tuple&& __t)
> noexcept(__unpack_std_tuple<is_nothrow_constructible, _Tp, _Tuple>)
> +#ifdef __cpp_concepts // >= C++20
> + -> _Tp
> + requires __can_make_from_tuple<_Tp, _Tuple>
> +#else
> + -> __enable_if_t<__can_make_from_tuple<_Tp, _Tuple>, _Tp>
> +#endif
> {
> constexpr size_t __n = tuple_size_v<remove_reference_t<_Tuple>>;
> #if __has_builtin(__reference_constructs_from_temporary)
> diff --git a/libstdc++-v3/testsuite/20_util/tuple/dr3528.cc
> b/libstdc++-v3/testsuite/20_util/tuple/dr3528.cc
> new file mode 100644
> index 000000000000..a96c6b75e209
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/20_util/tuple/dr3528.cc
> @@ -0,0 +1,44 @@
> +// { dg-do compile { target c++17 } }
> +
> +// LWG 3528. make_from_tuple can perform (the equivalent of) a C-style
> cast
> +
> +#include <tuple>
> +#include <array>
> +#include <utility>
> +
> +template<typename T, typename Tuple>
> +using make_t = decltype(std::make_from_tuple<T>(std::declval<Tuple>()));
> +
> +template<typename T, typename Tuple, typename = void>
> +constexpr bool can_make = false;
> +template<typename T, typename Tuple>
> +constexpr bool can_make<T, Tuple, std::void_t<make_t<T, Tuple>>> = true;
> +
> +static_assert( can_make<int, std::tuple<int>> );
> +static_assert( can_make<int, std::tuple<int>&> );
> +static_assert( can_make<int, const std::tuple<int>&> );
> +static_assert( can_make<int, std::array<short, 1>> );
> +static_assert( can_make<int, const std::array<short, 1>&&> );
> +static_assert( can_make<std::tuple<int, int>, std::pair<unsigned, long>>
> );
> +static_assert( can_make<const int*, std::tuple<int*>> );
> +static_assert( can_make<void*, std::tuple<int*>> );
> +static_assert( can_make<int, std::tuple<>> );
> +static_assert( ! can_make<int, std::tuple<int, int>> );
> +static_assert( ! can_make<int, std::pair<short, char>> );
> +static_assert( ! can_make<int, std::pair<short, char>&> );
> +static_assert( ! can_make<int, std::tuple<const char*>> );
> +static_assert( ! can_make<int*, std::tuple<const int*>> );
> +static_assert( ! can_make<int*, std::tuple<void*>> );
> +static_assert( ! can_make<int, std::array<int, 2>> );
> +static_assert( ! can_make<void, std::tuple<>> );
> +static_assert( ! can_make<void, std::array<int, 1>> );
> +
> +struct Two
> +{
> + Two(const char*, int);
> +};
> +
> +static_assert( can_make<Two, std::tuple<char*, unsigned>> );
> +static_assert( ! can_make<Two, std::tuple<const char*, int, int>> );
> +static_assert( can_make<Two, std::pair<const char*, long>> );
> +static_assert( ! can_make<Two, std::pair<int*, long>> );
> --
> 2.49.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250610/5391f0d5/attachment-0001.htm>
More information about the Libstdc++
mailing list