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&&...>
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
, andT
occurs exactly once inTypes...
.
emplace
(Idx, normal form) has a both a Requires and a SFINAE condition:
Requires:
Remarks: […] unlessI < sizeof...(Types)
is_constructible_v<T, Args...>
istrue
, andT
occurs exactly once inTypes...
.
emplace
(T
, initializer_list
form) has a SFINAE condition:
Remarks: […] unless
is_constructible_v<T, initializer_list<U>&, Args...>
istrue
, andT
occurs exactly once inTypes...
.
emplace
(Idx, initializer_list
form) has a both a Requires and a SFINAE condition:
Requires:
Remarks: […] unlessI < sizeof...(Types)
is_constructible_v<T, Args...>
is true, andT
occurs 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_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.
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<U> 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
, andT
occurs exactly once inTypes
.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...>
istrue
, andT
occurs exactly once inTypes
.template<size_t I, class... Args> variant_alternative_t<I, variant<Types...>>& emplace(Args&&... args);-6- Constraints:
-5- Mandates:I < sizeof...(Types)
.is_constructible_v<TI, Args...>
istrue
andI < sizeof...(Types)
istrue
. […]template<size_t I, class U, class... Args> variant_alternative_t<I, variant<Types...>>& emplace(initializer_list<U> il, Args&&... args);-13- Constraints:
-12- Mandates:I < sizeof...(Types)
.is_constructible_v<TI, initializer_list<U>&, Args...>
istrue
andI < sizeof...(Types)
istrue
. […]