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

### 2746. Inconsistency between requirements for `emplace` between `optional` and `variant`

Section: 22.5.3.4 [optional.assign], 22.6.3.5 [variant.mod], 22.7.4.4 [any.modifiers] Status: New Submitter: Richard Smith Opened: 2016-07-13 Last modified: 2020-05-10

Priority: 3

View all issues with New status.

Discussion:

Referring to N4604:

In [optional.object.assign]: `emplace` (normal form) has a Requires that the construction works.

> Requires: `is_constructible_v<T, Args&&...>` is `true`.

`emplace` (`initializer_list` form) has a SFINAE condition:

> Remarks: […] unless `is_constructible_v<T, initializer_list<U>&, Args&&...>` is `true`.

In 22.7.4.4 [any.modifiers]: `emplace` (normal form) has a Requires that the construction works:

> Requires: `is_constructible_v<T, Args...>` is `true`.

`emplace` (`initializer_list` form) has a SFINAE condition:

> Remarks: […] unless `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`.

In 22.6.3.5 [variant.mod]: `emplace` (`T`, normal form) has a SFINAE condition:

> Remarks: […] unless `is_constructible_v<T, Args...>` is `true`, and `T` occurs exactly once in `Types...`.

`emplace` (Idx, normal form) has a both a Requires and a SFINAE condition:

> Requires: `I < sizeof...(Types)`

> Remarks: […] unless `is_constructible_v<T, Args...>` is `true`, and `T` occurs exactly once in `Types...`.

`emplace` (`T`, `initializer_list` form) has a SFINAE condition:

> Remarks: […] unless `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`, and `T` occurs exactly once in `Types...`.

`emplace` (Idx, `initializer_list` form) has a both a Requires and a SFINAE condition:

> Requires: `I < sizeof...(Types)`

> Remarks: […] unless `is_constructible_v<T, Args...>` is true, and `T` occurs exactly once in `Types...`.

Why the inconsistency? Should all the cases have a SFINAE requirement?

I see that variant has an additional requirement (`T` occurs exactly once in `Types...`), but that only agues that it must be a SFINAE condition — doesn't say that the other cases (any/variant) should not.

`map`/`multimap`/`unordered_map`/`unordered_multimap` have SFINAE'd versions of `emplace` that don't take `initializer_list`s, but they don't have any `emplace` versions that take ILs.

Suggested resolution:

Add SFINAE requirements to `optional::emplace(Args&&... args)` and `any::emplace(Args&&... args);`

[2016-08 Chicago]

During issue prioritization, people suggested that this might apply to `any` as well.

Ville notes that 2746, 2754 and 2756 all go together.

[2020-05-10; Daniel comments and provides wording]

The inconsistency between the two `any::emplace` overloads have been removed by resolving LWG 2754 to use Constraints: elements. The last Mandating paper (P1460R1), adopted in Prague, changed the Requires: elements for `variant::emplace`, "`I < sizeof...(Types)`" to Mandates:, but that paper was focused on fixing inappropriate preconditions, not searching for consistency here. Given that the `in_place_index_t` constructors of `variant` uses SFINAE-conditions for this form of static precondition violation, I recommend that its `emplace` functions use the same style, which would bring them also in consistency with their corresponding type-based `emplace` forms that are Mandates:-free but delegate to the index-based forms.

Proposed resolution:

This wording is relative to N4861.

1. Modify 22.5.3.4 [optional.assign], as indicated:

   >     template<class... Args> T& emplace(Args&&... args);

   > > -29- Mandates Constraints: `is_constructible_v<T, Args...>` is `true`.

   > > […]

   >     template<class U, class... Args> T& emplace(initializer_list<U> il, Args&&... args);

   > > -35- Constraints: `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`.

   > > […]

2. Modify 22.6.3.5 [variant.mod], as indicated:

   >     template<class T, class... Args> T& emplace(Args&&... args);

   > > -1- Constraints: `is_constructible_v<T, Args...>` is `true`, and `T` occurs exactly once in `Types`.

   > > […]

   >     template<class T, class U, class... Args> T& emplace(initializer_list<U> il, Args&&... args);

   > > -3- Constraints: `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`, and `T` occurs exactly once in `Types`.

   > > […]

   >     template<size_t I, class... Args>
   >       variant_alternative_t<I, variant<Types...>>& emplace(Args&&... args);

   > > -5- Mandates: `I < sizeof...(Types)`.

   > > -6- Constraints: `is_constructible_v<TI, Args...>` is `true` and `I < sizeof...(Types)` is `true`.

   > > […]

   >     template<size_t I, class U, class... Args>
   >       variant_alternative_t<I, variant<Types...>>& emplace(initializer_list<U> il, Args&&... args);

   > > -12- Mandates: `I < sizeof...(Types)`.

   > > -13- Constraints: `is_constructible_v<TI, initializer_list<U>&, Args...>` is `true` and `I < sizeof...(Types)` is `true`.

   > > […]