Issue 2754: The in_place constructors and emplace functions added by P0032R3 don't require CopyConstructible (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 Resolved status.
2754. The 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.
They must. Otherwise copying an any that's made to hold a non-CopyConstructibletype 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 twoemplace 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 decayed 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(i), 2754(i) and 2756(i) 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_constructibleand 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
anysynopsis, 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, Args&&...);[…]
template <classTValueType, class... Args>
void emplace(Args&& ...);
template <classTValueType, class U, class... Args>
void emplace(initializer_list, Args&&...);
[…]
};- Change 22.7.4.2 [any.cons] as indicated:
template
any(ValueType&& value);-6- Let
Tbe equal todecay_t<ValueType>.-7- Requires:
Tshall satisfy theCopyConstructiblerequirements.Ifis_copy_constructible_v<T>isfalse, the program is ill-formed.[…]
-9- Remarks: This constructor shall not participate in overload resolution
ifunlessdecay_t<ValueType>is not the same type asanyandis_copy_constructible_v<T>istrue.template <class
TValueType, class... Args>
explicit any(in_place_type_t<TValueType>, Args&&... args);-?- Let
Tbe equal toremove_cv_t<ValueType>.-11- Requires:
Tshall satisfy theCopyConstructiblerequirements.is_constructible_v<T, Args...>istrue[…]
-?- Remarks: This constructor shall not participate in overload resolution unless
is_reference_v<T>isfalse,is_array_v<T>isfalse,is_function_v<T>isfalse,is_copy_constructible_v<T>istrueandis_constructible_v<T, Args...>istrue.template <class
TValueType, class U, class... Args>
explicit any(in_place_type_t<TValueType>, initializer_list il, Args&&... args);-?- Let
Tbe equal toremove_cv_t<ValueType>.-15- Requires:
Tshall satisfy theCopyConstructiblerequirements.is_constructible_v<T, initializer_list<U>&, Args...>istrue[…]
-19- Remarks: The function shall not participate in overload resolution unless
is_reference_v<T>isfalse,is_array_v<T>isfalse,is_function_v<T>isfalse,is_copy_constructible_v<T>istrueandis_constructible_v<T, initializer_list<U>&, Args...>istrue.- Change 22.7.4.3 [any.assign] as indicated:
template
any& operator=(ValueType&& rhs);-7- Let
Tbe equal todecay_t<ValueType>.-8- Requires:
Tshall satisfy theCopyConstructiblerequirements.Ifis_copy_constructible_v<T>isfalse, the program is ill-formed.[…]
-11- Remarks: This operator shall not participate in overload resolution
ifunlessdecay_t<ValueType>is not the same type asanyandis_copy_constructible_v<T>istrue.- Change 22.7.4.4 [any.modifiers] as indicated:
template <class
TValueType, class... Args>
void emplace(Args&&... args);-?- Let
Tbe equal toremove_cv_t<ValueType>.-1- Requires:
Tshall satisfy theCopyConstructiblerequirements.is_constructible_v<T, Args...>istrue[…]
-5- Remarks: If an exception is thrown during the call to
T's constructor,*thisdoes 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>istrueandis_constructible_v<T, Args...>istrue.template <class
TValueType, class U, class... Args>
void emplace(initializer_list il, Args&&... args);-?- Let
Tbe equal toremove_cv_t<ValueType>.-?- Requires:
Tshall satisfy theCopyConstructiblerequirements.-6- Effects: […]
[…]
-9- Remarks: If an exception is thrown during the call to
T's constructor,*thisdoes 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>istrueandis_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
CopyConstructibleto the _Requires_-clauses.
Rationale:anydoesn't care whether the type it holds satisfies the semantic requirements of theCopyConstructibleconcept. The syntactic requirements are now SFINAE constraints in _Requires_-clauses. - It reverts back towards
decay_trather thanremove_cv_t, and does_not_ add the suggested SFINAE constraints foris_reference/is_array/is_function.
Rationale:anydecays by design. It's to some extent inconsistent to not protect against decay in theValueTypeconstructor/assignment operator, but to protect against decay in thein_place_tconstructors andemplacefunctions- I think it's saner to just decay than to potentially run into situations where I need to
remove_referenceinsidein_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
anysynopsis, 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, Args&&...);[…]
template <classTValueType, class... Args>
void emplace(Args&& ...);
template <classTValueType, class U, class... Args>
void emplace(initializer_list, Args&&...);
[…]
};- Change 22.7.4.2 [any.cons] as indicated:
template
any(ValueType&& value);-6- Let
Tbe equal todecay_t<ValueType>.
-7- Requires:Tshall satisfy theCopyConstructiblerequirements. Ifis_copy_constructible_v<T>isfalse, the program is ill-formed.[…]
-9- Remarks: This constructor shall not participate in overload resolution
ifunlessdecay_t<ValueType>is not the same type asanyandis_copy_constructible_v<T>istrue.template <class
TValueType, class... Args>
explicit any(in_place_type_t<TValueType>, Args&&... args);-?- Let
Tbe equal todecay_t<ValueType>.
-11- Requires:.is_constructible_v<T, Args...>istrue[…]
-?- Remarks: This constructor shall not participate in overload resolution unless
is_copy_constructible_v<T>istrueandis_constructible_v<T, Args...>istrue.template <class
TValueType, class U, class... Args>
explicit any(in_place_type_t<TValueType>, initializer_list il, Args&&... args);-?- Let
Tbe equal todecay_t<ValueType>.
-15- Requires:.is_constructible_v<T, initializer_list<U>&, Args...>istrue[…]
-19- Remarks: The function shall not participate in overload resolution unless
is_copy_constructible_v<T>istrueandis_constructible_v<T, initializer_list<U>&, Args...>istrue.- Change 22.7.4.3 [any.assign] as indicated:
template
any& operator=(ValueType&& rhs);-7- Let
Tbe equal todecay_t<ValueType>.
-8- Requires:Tshall satisfy theCopyConstructiblerequirements. Ifis_copy_constructible_v<T>isfalse, the program is ill-formed.[…]
-11- Remarks: This operator shall not participate in overload resolution
ifunlessdecay_t<ValueType>is not the same type asanyandis_copy_constructible_v<T>istrue.- Change 22.7.4.4 [any.modifiers] as indicated:
template <class
TValueType, class... Args>
void emplace(Args&&... args);-?- Let
Tbe equal todecay_t<ValueType>.
-1- Requires:.is_constructible_v<T, Args...>istrue[…]
-5- Remarks: If an exception is thrown during the call to
T's constructor,*thisdoes 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>istrueandis_constructible_v<T, Args...>istrue.template <class
TValueType, class U, class... Args>
void emplace(initializer_list il, Args&&... args);-?- Let
Tbe equal todecay_t<ValueType>.-6- Effects: […]
[…]
-9- Remarks: If an exception is thrown during the call to
T's constructor,*thisdoes 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>istrueandis_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(i), 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
anysynopsis, 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, Args&&...);[…]
template <classTValueType, class... Args>
void emplace(Args&& ...);
template <classTValueType, class U, class... Args>
void emplace(initializer_list, Args&&...);
[…]
}; - Change 22.7.4.2 [any.cons] as indicated:
template
any(ValueType&& value);-6- Let
Tbedecay_t<ValueType>.-7- Requires:
Tshall satisfy theCopyConstructiblerequirements.Ifis_copy_constructible_v<T>isfalse, the program is ill-formed.[…]
-9- Remarks: This constructor shall not participate in overload resolution
ifunlessT~~decay_t<ValueType>~~is not the same type asanyandis_copy_constructible_v<T>istrue.template <class
TValueType, class... Args>
explicit any(in_place_type_t<TValueType>, Args&&... args);-?- Let
Tbedecay_t<ValueType>.-11- Requires:
Tshall satisfy theCopyConstructiblerequirements.is_constructible_v<T, Args...>istrue[…]
-?- Remarks: This constructor shall not participate in overload resolution unless
is_copy_constructible_v<T>istrueandis_constructible_v<T, Args...>istrue.template <class
TValueType, class U, class... Args>
explicit any(in_place_type_t<TValueType>, initializer_list il, Args&&... args);-?- Let
Tbedecay_t<ValueType>.-15- Requires:
Tshall satisfy theCopyConstructiblerequirements.is_constructible_v<T, initializer_list<U>&, Args...>istrue[…]
-19- Remarks: The function shall not participate in overload resolution unless
is_copy_constructible_v<T>istrueandis_constructible_v<T, initializer_list<U>&, Args...>istrue. - Change 22.7.4.3 [any.assign] as indicated:
template
any& operator=(ValueType&& rhs);-7- Let
Tbedecay_t<ValueType>.-8- Requires:
Tshall satisfy theCopyConstructiblerequirements.Ifis_copy_constructible_v<T>isfalse, the program is ill-formed.[…]
-11- Remarks: This operator shall not participate in overload resolution
ifunlessT~~decay_t<ValueType>~~is not the same type asanyandis_copy_constructible_v<T>istrue. - Change 22.7.4.4 [any.modifiers] as indicated:
template <class
TValueType, class... Args>
void emplace(Args&&... args);-?- Let
Tbedecay_t<ValueType>.-1- Requires:
Tshall satisfy theCopyConstructiblerequirements.is_constructible_v<T, Args...>istrue[…]
-5- Remarks: If an exception is thrown during the call to
T's constructor,*thisdoes 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>istrueandis_constructible_v<T, Args...>istrue.template <class
TValueType, class U, class... Args>
void emplace(initializer_list il, Args&&... args);-?- Let
Tbedecay_t<ValueType>.-?- Requires:
Tshall satisfy theCopyConstructiblerequirements.-6- Effects: […]
[…]
-9- Remarks: If an exception is thrown during the call to
T's constructor,*thisdoes 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>istrueandis_constructible_v<T, initializer_list<U>&, Args...>istrue.