C++ Logo


Advanced search

Re: [std-proposals] Make std::make_from_tuple SFINAE friendly

From: F. v.S. <de34_at_[hidden]>
Date: Mon, 1 Apr 2024 06:34:05 +0000
This is somehow unclear when the constraints are not literally specified with "Constraints:" in the standard wording ([structure.specifications]/4). At least "Equivalent to" doesn't propagate every substitution failure in immediate context. E.g. it's noted in https://github.com/cplusplus/draft/pull/6900#discussion_r1537381337 that the ill-formedness of destructor call shouldn't participate in SFINAE.

In the case of std::make_from_tuple/LWG3528, the constrains of apply-impl, the constraints were introduced via a requires-clause but not literal "Constraints". Some implementors believed the requires-clause should be treated same as Constraints, but this is not explicitly stated.

Also, if it's intended to make std::make_from_tuple SFINAE-friendly, the Mandates should be turned into Constraints...

Jiang An
From: Std-Proposals <std-proposals-bounces_at_lists.isocpp.org> on behalf of Jonathan Wakely via Std-Proposals <std-proposals_at_[hidden]>
Sent: Monday, April 1, 2024 3:01
To: std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Cc: Jonathan Wakely <cxx_at_kayari.org>
Subject: Re: [std-proposals] Make std::make_from_tuple SFINAE friendly

On Fri, 29 Mar 2024 at 15:29, Yrong via Std-Proposals <std-proposals_at_[hidden]<mailto:std-proposals_at_[hidden]>> wrote:

I was wondering if I can submit this improvement as a short proposal paper.


LWG3528 constraint `constexpr T make-from-tuple-impl(Tuple&& t, index_sequence<I...>)` with `requires is_constructible_v<T, decltype(get<I>(declval<Tuple>()))...>`.
When someone write SFINAE code like below to check whether T can make from tuple, they may meet hard errors like "no matching function for call to 'make-from-tuple-impl'...".

template <class T, class Tuple, class = void>
inline constexpr bool has_make_from_tuple = false;

template <class T, class Tuple>
inline constexpr bool
has_make_from_tuple<T, Tuple, std::void_t<decltype(std::make_from_tuple<T>(std::declval<Tuple>()))>> = true;

struct A { int a; };

static_assert(!has_make_from_tuple<int*, std::tuple<A*>>);

Proposed resolution:

This wording is relative to N4971<https://wg21.link/N4971>.

  1. Edit 22.4.6 [tuple.apply]<https://wg21.link/tuple.apply> as indicated:

template<class T, tuple-like<https://eel.is/c++draft/tuple.like#concept:tuple-like> Tuple> constexpr T make_from_tuple(Tuple&& t); -3- Let I be the pack 0, 1, ..., (tuple_size_v<remove_reference_t<Tuple>> - 1).-4- Constraints: is_constructible_v<T, decltype(get<I>(declval<Tuple>()))...> is true.
-5- Mandates: If tuple_size_v<remove_reference_t<Tuple>> is 1, then reference_constructs_from_temporary_v<T, decltype(get<0>(declval<Tuple>()))> is false.<https://eel.is/c++draft/tuple.apply#3.sentence-1>
-6- Effects: Given the exposition-only function template:
namespace std { template<class T, tuple-like<https://eel.is/c++draft/tuple.like#concept:tuple-like> Tuple, size_t... I> requires is_constructible_v<T, decltype(get<I>(declval<Tuple>()))...> constexpr T make-from-tuple-impl(Tuple&& t, index_sequence<I...>) { // exposition only return T(get<I>(std::forward<Tuple>(t))...); } }
Equivalent to:return make-from-tuple-impl<T>( std::forward<Tuple>(t), make_index_sequence<tuple_size_v<remove_reference_t<Tuple>>>{});
[Note 1:
The type of T must be supplied as an explicit template parameter, as it cannot be deduced from the argument list.<https://eel.is/c++draft/tuple#apply-4.sentence-2>
 — end note]

If the effects are "Equivalent to" calling a constrained function, don't the constraints apply to std::make_from_tuple already?

Received on 2024-04-01 06:34:16