Issue 2746: Inconsistency between requirements for emplace between optional and variant (original) (raw)
This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Ready 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: Ready Submitter: Richard Smith Opened: 2016-07-13 Last modified: 2025-12-05
Priority: 3
View all issues with Ready 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&&...>istrue.
emplace (initializer_list form) has a SFINAE condition:
Remarks: […] unless
is_constructible_v<T, initializer_list<U>&, Args&&...>istrue.
In 22.7.4.4 [any.modifiers]: emplace (normal form) has a Requires that the construction works:
Requires:
is_constructible_v<T, Args...>istrue.
emplace (initializer_list form) has a SFINAE condition:
Remarks: […] unless
is_constructible_v<T, initializer_list<U>&, Args...>istrue.
In 22.6.3.5 [variant.mod]: emplace (T, normal form) has a SFINAE condition:
Remarks: […] unless
is_constructible_v<T, Args...>istrue, andToccurs exactly once inTypes....
emplace (Idx, normal form) has a both a Requires and a SFINAE condition:
Requires:
I < sizeof...(Types)Remarks: […] unless
is_constructible_v<T, Args...>istrue, andToccurs exactly once inTypes....
emplace (T, initializer_list form) has a SFINAE condition:
Remarks: […] unless
is_constructible_v<T, initializer_list<U>&, Args...>istrue, andToccurs exactly once inTypes....
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, andToccurs exactly once inTypes....
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_lists, 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(i), 2754(i) and 2756(i) all go together.
[2020-05-10; Daniel comments and provides wording]
The inconsistency between the two any::emplace overloads have been removed by resolving LWG2754(i) 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 thein_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.
Previous resolution [SUPERSEDED]:
This wording is relative to N4861.
- Modify 22.5.3.4 [optional.assign], as indicated:
template<class... Args> T& emplace(Args&&... args);
-29-
MandatesConstraints:is_constructible_v<T, Args...>istrue.[…]
template<class U, class... Args> T& emplace(initializer_list il, Args&&... args);
-35- Constraints:
is_constructible_v<T, initializer_list<U>&, Args...>istrue.[…]
- 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...>istrue, andToccurs exactly once inTypes.[…]
template<class T, class U, class... Args> T& emplace(initializer_list il, Args&&... args);
-3- Constraints:
is_constructible_v<T, initializer_list<U>&, Args...>istrue, andToccurs exactly once inTypes.[…]
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<T_I_, Args...>istrueandI < sizeof...(Types)istrue.[…]
template<size_t I, class U, class... Args>
variant_alternative_t<I, variant<Types...>>& emplace(initializer_list il, Args&&... args);
-12- Mandates:I < sizeof...(Types).-13- Constraints:
is_constructible_v<T_I_, initializer_list<U>&, Args...>istrueandI < sizeof...(Types)istrue.[…]
[2025-12-05; Jonathan provides new wording]
There's no need to use SFINAE to check if a variant with N alternatives allows you to emplace the N+1th alternative.
[2025-12-05; LWG telecon. Moved to Ready]
Proposed resolution:
This wording is relative to N5014.
- Modify 22.5.3.4 [optional.assign], as indicated:
template<class... Args> T& emplace(Args&&... args);
-29-
MandatesConstraints:is_constructible_v<T, Args...>istrue.[…]
template<class U, class... Args> T& emplace(initializer_list il, Args&&... args);
-35- Constraints:
is_constructible_v<T, initializer_list<U>&, Args...>istrue.[…]