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...

Thanks,

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:

Hello,

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

Discussion:

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?

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...

Thanks,

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:

Hello,

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

Discussion:

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