This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of NAD status.

### 3440. Aggregate-paren-init breaks direct-initializing a `tuple` or `optional` from `{aggregate-member-value}`

Section: 20.5.3.1 [tuple.cnstr], 20.6.3.2 [optional.ctor] Status: NAD Submitter: Ville Voutilainen Opened: 2020-05-01 Last modified: 2020-11-09

Priority: 2

View other active issues in [tuple.cnstr].

View all other issues in [tuple.cnstr].

View all issues with NAD status.

Discussion:

For reference, see this gcc bug report.

Constructing a `tuple` or `optional` from an element value of an aggregate is broken in C++20. `tuple<c> t({val});` and `optional<c> t({val});` invoked a non-forwarding constructor before, but now the perfect-forwarding converting constructors are a match, because the element is constructible from `{val}`. But it's not convertible, so overload resolution chooses the explicit constructor, and the initialization fails.

Tim Song explains the overload resolution in this reflector discussion.

Now that we understand that C++17 called the non-forwarding conversion constructor, and C++20 tries to use the forwarding conversion constructor, we have the solution. SFINAE away the forwarding conversion constructor when it would convert an aggregate.

This also means that `tuple<c> t(0);` won't work, which is unfortunate because `tuple<c>/optional<c>` no longer mirrors what `c` can do. That's okay; in this LWG issue, we first restore feature parity with C++17, and later, as an extension, enable such initializations so that `tuple`/`optional` mirrors what `c` can do in C++20.

The proposed wording below has been implemented and tested.

[2020-05-09; Reflector prioritization]

Set priority to 2 after reflector discussions.

[2020-06-11; LWG Telecon: Status changed: New → LEWG.]

Ask LEWG if it's desirable to make `({val})` work again. Tomasz would prefer it to be explicit e.g. via `std::in_place`.

[2020-06-23; LEWG Telecon]

POLL: Make `({val})` work again, at the risk of non-transparency of tuple constructors and further complicating the tuple and optional overload set.

    SF F N A SA
    0  5 6 9 0

No consensus for change. Close as Not a defect.

[2020-11-09 Status changed: Tentatively NAD → NAD.]

Proposed resolution:

This wording is relative to N4861.

1. Modify 20.5.3.1 [tuple.cnstr] as indicated:

   >     template<class... UTypes> constexpr explicit(see below) tuple(UTypes&&... u);

   > > -11- Constraints: `sizeof...(Types)` equals `sizeof...(UTypes)` and `sizeof...(Types) ≥ 1` and `is_constructible_v<Ti, Ui>` is `true` for all `i` and `conjunction_v<is_aggregate<remove_reference_t<Ti>>, negation<is_same<remove_reference_t<Ti>, remove_reference_t<Ui>>>>` is `false` for all `i`.

2. Modify 20.6.3.2 [optional.ctor] as indicated:

   >     template<class U = T> constexpr explicit(see below) optional(U&& v);

   > > -22- Constraints: `is_constructible_v<T, U>` is `true`, `is_same_v<remove_cvref_t<U>, in_place_t>` is `false`, and `is_same_v<remove_cvref_t<U>, optional>` is `false`, and `conjunction_v<is_aggregate<T>, negation<is_same<T, remove_reference_t<U>>>>` is `false`.