in_place
constructors and emplace
functions added by P0032R3 don't require CopyConstructible
Section: 22.7.4.2 [any.cons], 22.7.4.3 [any.assign], 22.7.4.4 [any.modifiers] Status: Resolved Submitter: Ville Voutilainen Opened: 2016-07-05 Last modified: 2020-09-06
Priority: 1
View all other issues in [any.cons].
View all issues with Resolved status.
Discussion:
The in_place
constructors and emplace
functions
added by P0032R3 don't require CopyConstructible
.
any
that's made to hold a non-CopyConstructible
type must fail with a run-time error. Since that's crazy, we want to prevent
storing non-CopyConstructible
types in an any
.
Previously, the requirement for CopyConstructible
was just on the converting
constructor template and the converting assignment operator template on any
.
Now that we are adding two in_place
constructor overloads and two
emplace
overloads, it seems reasonable to require CopyConstructible
in some more
general location, in order to avoid repeating that requirement all over the place.
[2016-07 — Chicago]
Monday: P1
Tuesday: Ville/Billy/Billy provide wording
[2016-08-02: Daniel comments]
The P/R wording of this issue brought to my intention that the recently added emplace
functions
of std::any
introduced a breakage of a previous class invariant that only a decay
ed type could
be stored as object into an any
, this prevented storing arrays, references, functions, and cv-qualified
types. The new constraints added my Ville do prevent some of these types (e.g. neither arrays nor functions meet
the CopyConstructible
requirements), but we need to cope with cv-qualified types and reference types.
[2016-08-02: Agustín K-ballo Bergé comments]
Presumably the constructors any(in_place_type_t<T>, ...)
would need to be modified in the same way
the emplace
overloads were.
[2016-08-02: Ville adjusts the P/R to cope with the problems pointed out by Daniel's and Agustín's comments]
Ville notes that 2746, 2754 and 2756 all go together.
Previous resolution [SUPERSEDED]:
This wording is relative to N4606.
Drafting note: this P/R doesn't turn the Requires-clauses into Remarks-clauses. We might want to do that separately, because SFINAEing the constructors allows users to query for
is_constructible
and get the right answer. Failing to mandate the SFINAE will lead to non-portable answers foris_constructible
. Currently, libstdc++ SFINAEs. That should be done as a separate issue, as this issue is an urgent bug-fix but the mandated SFINAE is not.
Change 22.7.4 [any.class], class
any
synopsis, as indicated:class any { public: […] template <classTValueType, class... Args> explicit any(in_place_type_t<TValueType>, Args&&...); template <classTValueType, class U, class... Args> explicit any(in_place_type_t<TValueType>, initializer_list<U>, Args&&...); […] template <classTValueType, class... Args> void emplace(Args&& ...); template <classTValueType, class U, class... Args> void emplace(initializer_list<U>, Args&&...); […] };Change 22.7.4.2 [any.cons] as indicated:
template<class ValueType> any(ValueType&& value);-6- Let
-7- Requires:T
be equal todecay_t<ValueType>
.T
shall satisfy theCopyConstructible
requirements.If[…] -9- Remarks: This constructor shall not participate in overload resolutionis_copy_constructible_v<T>
isfalse
, the program is ill-formed.ifunlessdecay_t<ValueType>
is not the same type asany
andis_copy_constructible_v<T>
istrue
.template <classTValueType, class... Args> explicit any(in_place_type_t<TValueType>, Args&&... args);-?- Let
-11- Requires:T
be equal toremove_cv_t<ValueType>
.T
shall satisfy theCopyConstructible
requirements. […] -?- Remarks: This constructor shall not participate in overload resolution unlessis_constructible_v<T, Args...>
istrue
is_reference_v<T>
isfalse
,is_array_v<T>
isfalse
,is_function_v<T>
isfalse
,is_copy_constructible_v<T>
istrue
andis_constructible_v<T, Args...>
istrue
.template <classTValueType, class U, class... Args> explicit any(in_place_type_t<TValueType>, initializer_list<U> il, Args&&... args);-?- Let
-15- Requires:T
be equal toremove_cv_t<ValueType>
.T
shall satisfy theCopyConstructible
requirements. […] -19- Remarks: The function shall not participate in overload resolution unlessis_constructible_v<T, initializer_list<U>&, Args...>
istrue
is_reference_v<T>
isfalse
,is_array_v<T>
isfalse
,is_function_v<T>
isfalse
,is_copy_constructible_v<T>
istrue
andis_constructible_v<T, initializer_list<U>&, Args...>
istrue
.Change 22.7.4.3 [any.assign] as indicated:
template<class ValueType> any& operator=(ValueType&& rhs);-7- Let
-8- Requires:T
be equal todecay_t<ValueType>
.T
shall satisfy theCopyConstructible
requirements.If[…] -11- Remarks: This operator shall not participate in overload resolutionis_copy_constructible_v<T>
isfalse
, the program is ill-formed.ifunlessdecay_t<ValueType>
is not the same type asany
andis_copy_constructible_v<T>
istrue
.Change 22.7.4.4 [any.modifiers] as indicated:
template <classTValueType, class... Args> void emplace(Args&&... args);-?- Let
-1- Requires:T
be equal toremove_cv_t<ValueType>
.T
shall satisfy theCopyConstructible
requirements. […] -5- Remarks: If an exception is thrown during the call tois_constructible_v<T, Args...>
istrue
T
's constructor,*this
does not contain a value, and any previously contained object has been destroyed. This function shall not participate in overload resolution unlessis_reference_v<T>
isfalse
,is_array_v<T>
isfalse
,is_function_v<T>
isfalse
,is_copy_constructible_v<T>
istrue
andis_constructible_v<T, Args...>
istrue
.template <classTValueType, class U, class... Args> void emplace(initializer_list<U> il, Args&&... args);-?- Let
-?- Requires:T
be equal toremove_cv_t<ValueType>
.T
shall satisfy theCopyConstructible
requirements. -6- Effects: […] […] -9- Remarks: If an exception is thrown during the call toT
's constructor,*this
does not contain a value, and any previously contained object has been destroyed. The function shall not participate in overload resolution unlessis_reference_v<T>
isfalse
,is_array_v<T>
isfalse
,is_function_v<T>
isfalse
,is_copy_constructible_v<T>
istrue
andis_constructible_v<T, initializer_list<U>&, Args...>
istrue
.
[2016-08-03: Ville comments and revises his proposed wording]
After discussing the latest P/R, here's an update. What this update does is that:
It strikes the Requires-clauses and does not add
CopyConstructible
to the Requires-clauses.
any
doesn't care whether the type it holds satisfies the
semantic requirements of the CopyConstructible
concept. The syntactic
requirements are now SFINAE constraints in Requires-clauses.It reverts back towards decay_t
rather than remove_cv_t
, and does
not add the suggested SFINAE constraints for is_reference
/is_array
/is_function
.
any
decays by design. It's to some extent inconsistent
to not protect against decay in the ValueType
constructor/assignment operator, but to protect
against decay in the in_place_t
constructors and emplace
functions
I think it's saner to just decay than to potentially run into
situations where I need to remove_reference
inside in_place_t
.
Based on that, this P/R should supersede the previous one. We want to look at this new P/R in LWG and potentially send it to LEWG for verification. Personally, I think this P/R is the more conservative one, doesn't add significant new functionality, and is consistent, and is thus not really Library-Evolutionary.
Previous resolution [SUPERSEDED]:
This wording is relative to N4606.
Change 22.7.4 [any.class], class
any
synopsis, as indicated:class any { public: […] template <classTValueType, class... Args> explicit any(in_place_type_t<TValueType>, Args&&...); template <classTValueType, class U, class... Args> explicit any(in_place_type_t<TValueType>, initializer_list<U>, Args&&...); […] template <classTValueType, class... Args> void emplace(Args&& ...); template <classTValueType, class U, class... Args> void emplace(initializer_list<U>, Args&&...); […] };Change 22.7.4.2 [any.cons] as indicated:
template<class ValueType> any(ValueType&& value);-6- Let
T
be equal todecay_t<ValueType>
.-7- Requires:[…] -9- Remarks: This constructor shall not participate in overload resolutionT
shall satisfy theCopyConstructible
requirements. Ifis_copy_constructible_v<T>
isfalse
, the program is ill-formed.ifunlessdecay_t<ValueType>
is not the same type asany
andis_copy_constructible_v<T>
istrue
.template <classTValueType, class... Args> explicit any(in_place_type_t<TValueType>, Args&&... args);-?- Let
T
be equal todecay_t<ValueType>
.-11- Requires:. […] -?- Remarks: This constructor shall not participate in overload resolution unlessis_constructible_v<T, Args...>
istrue
is_copy_constructible_v<T>
istrue
andis_constructible_v<T, Args...>
istrue
.template <classTValueType, class U, class... Args> explicit any(in_place_type_t<TValueType>, initializer_list<U> il, Args&&... args);-?- Let
T
be equal todecay_t<ValueType>
.-15- Requires:. […] -19- Remarks: The function shall not participate in overload resolution unlessis_constructible_v<T, initializer_list<U>&, Args...>
istrue
is_copy_constructible_v<T>
istrue
andis_constructible_v<T, initializer_list<U>&, Args...>
istrue
.Change 22.7.4.3 [any.assign] as indicated:
template<class ValueType> any& operator=(ValueType&& rhs);-7- Let
T
be equal todecay_t<ValueType>
.-8- Requires:[…] -11- Remarks: This operator shall not participate in overload resolutionT
shall satisfy theCopyConstructible
requirements. Ifis_copy_constructible_v<T>
isfalse
, the program is ill-formed.ifunlessdecay_t<ValueType>
is not the same type asany
andis_copy_constructible_v<T>
istrue
.Change 22.7.4.4 [any.modifiers] as indicated:
template <classTValueType, class... Args> void emplace(Args&&... args);-?- Let
T
be equal todecay_t<ValueType>
.-1- Requires:. […] -5- Remarks: If an exception is thrown during the call tois_constructible_v<T, Args...>
istrue
T
's constructor,*this
does not contain a value, and any previously contained object has been destroyed. This function shall not participate in overload resolution unlessis_copy_constructible_v<T>
istrue
andis_constructible_v<T, Args...>
istrue
.template <classTValueType, class U, class... Args> void emplace(initializer_list<U> il, Args&&... args);-?- Let
-6- Effects: […] […] -9- Remarks: If an exception is thrown during the call toT
be equal todecay_t<ValueType>
.T
's constructor,*this
does not contain a value, and any previously contained object has been destroyed. The function shall not participate in overload resolution unlessis_copy_constructible_v<T>
istrue
andis_constructible_v<T, initializer_list<U>&, Args...>
istrue
.
[2016-08-03: Ville comments and revises his proposed wording]
This P/R brings back the CopyConstructible
parts of the relevant
Requires-clauses but removes the other parts of the Requires-clauses.
[2016-08 - Chicago]
Thurs PM: Moved to Tentatively Ready
[2016-11 - Issaquah]
Approved in plenary.
After plenary, there was concern about applying both this and 2744, so it was moved back to "Open". Then, when the concerns were resolved, moved to "Resolved".
Proposed resolution:
This wording is relative to N4606.
Change 22.7.4 [any.class], class any
synopsis, as indicated:
class any { public: […] template <classTValueType, class... Args> explicit any(in_place_type_t<TValueType>, Args&&...); template <classTValueType, class U, class... Args> explicit any(in_place_type_t<TValueType>, initializer_list<U>, Args&&...); […] template <classTValueType, class... Args> void emplace(Args&& ...); template <classTValueType, class U, class... Args> void emplace(initializer_list<U>, Args&&...); […] };
Change 22.7.4.2 [any.cons] as indicated:
template<class ValueType> any(ValueType&& value);-6- Let
-7- Requires:T
bedecay_t<ValueType>
.T
shall satisfy theCopyConstructible
requirements.If[…] -9- Remarks: This constructor shall not participate in overload resolutionis_copy_constructible_v<T>
isfalse
, the program is ill-formed.ifunlessT
is not the same type asdecay_t<ValueType>any
andis_copy_constructible_v<T>
istrue
.template <classTValueType, class... Args> explicit any(in_place_type_t<TValueType>, Args&&... args);-?- Let
-11- Requires:T
bedecay_t<ValueType>
.T
shall satisfy theCopyConstructible
requirements. […] -?- Remarks: This constructor shall not participate in overload resolution unlessis_constructible_v<T, Args...>
istrue
is_copy_constructible_v<T>
istrue
andis_constructible_v<T, Args...>
istrue
.template <classTValueType, class U, class... Args> explicit any(in_place_type_t<TValueType>, initializer_list<U> il, Args&&... args);-?- Let
-15- Requires:T
bedecay_t<ValueType>
.T
shall satisfy theCopyConstructible
requirements. […] -19- Remarks: The function shall not participate in overload resolution unlessis_constructible_v<T, initializer_list<U>&, Args...>
istrue
is_copy_constructible_v<T>
istrue
andis_constructible_v<T, initializer_list<U>&, Args...>
istrue
.
Change 22.7.4.3 [any.assign] as indicated:
template<class ValueType> any& operator=(ValueType&& rhs);-7- Let
-8- Requires:T
bedecay_t<ValueType>
.T
shall satisfy theCopyConstructible
requirements.If[…] -11- Remarks: This operator shall not participate in overload resolutionis_copy_constructible_v<T>
isfalse
, the program is ill-formed.ifunlessT
is not the same type asdecay_t<ValueType>any
andis_copy_constructible_v<T>
istrue
.
Change 22.7.4.4 [any.modifiers] as indicated:
template <classTValueType, class... Args> void emplace(Args&&... args);-?- Let
-1- Requires:T
bedecay_t<ValueType>
.T
shall satisfy theCopyConstructible
requirements. […] -5- Remarks: If an exception is thrown during the call tois_constructible_v<T, Args...>
istrue
T
's constructor,*this
does not contain a value, and any previously contained object has been destroyed. This function shall not participate in overload resolution unlessis_copy_constructible_v<T>
istrue
andis_constructible_v<T, Args...>
istrue
.template <classTValueType, class U, class... Args> void emplace(initializer_list<U> il, Args&&... args);-?- Let
-?- Requires:T
bedecay_t<ValueType>
.T
shall satisfy theCopyConstructible
requirements. -6- Effects: […] […] -9- Remarks: If an exception is thrown during the call toT
's constructor,*this
does not contain a value, and any previously contained object has been destroyed. The function shall not participate in overload resolution unlessis_copy_constructible_v<T>
istrue
andis_constructible_v<T, initializer_list<U>&, Args...>
istrue
.