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-`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 for `is_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.

> 1. Change 22.7.4 [any.class], class `any` synopsis, as indicated:

>    >     class any {
>    >     public:
>    >       […]
>    >       template <class TValueType, class... Args>
>    >         explicit any(in_place_type_t<TValueType>, Args&&...);
>    >       template <class TValueType, class U, class... Args>
>    >         explicit any(in_place_type_t<TValueType>, initializer_list<U>, Args&&...);

>    >       […]
>    >       template <class TValueType, class... Args>
>    >         void emplace(Args&& ...);
>    >       template <class TValueType, class U, class... Args>
>    >         void emplace(initializer_list<U>, Args&&...);
>    >       […]
>    >     };

> 2. Change 22.7.4.2 [any.cons] as indicated:

>    >     template<class ValueType>
>    >       any(ValueType&& value);

>    > > -6- Let `T` be equal to `decay_t<ValueType>`.

>    > > -7- Requires: `T` shall satisfy the `CopyConstructible` requirements. If `is_copy_constructible_v<T>` is `false`, the program is ill-formed.

>    > > […]

>    > > -9- Remarks: This constructor shall not participate in overload resolution if unless `decay_t<ValueType>` is not the same type as `any` and `is_copy_constructible_v<T>` is `true`.

>    >     template <class TValueType, class... Args>
>    >       explicit any(in_place_type_t<TValueType>, Args&&... args);

>    > > -?- Let `T` be equal to `remove_cv_t<ValueType>`.

>    > > -11- Requires: `T` shall satisfy the `CopyConstructible` requirements `is_constructible_v<T, Args...>` is `true`.

>    > > […]

>    > > -?- Remarks: This constructor shall not participate in overload resolution unless `is_reference_v<T>` is `false`, `is_array_v<T>` is `false`, `is_function_v<T>` is `false`, `is_copy_constructible_v<T>` is `true` and `is_constructible_v<T, Args...>` is `true`.

>    >     template <class TValueType, class U, class... Args>
>    >       explicit any(in_place_type_t<TValueType>, initializer_list<U> il, Args&&... args);

>    > > -?- Let `T` be equal to `remove_cv_t<ValueType>`.

>    > > -15- Requires: `T` shall satisfy the `CopyConstructible` requirements `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`.

>    > > […]

>    > > -19- Remarks: The function shall not participate in overload resolution unless `is_reference_v<T>` is `false`, `is_array_v<T>` is `false`, `is_function_v<T>` is `false`, `is_copy_constructible_v<T>` is `true` and `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`.

> 3. Change 22.7.4.3 [any.assign] as indicated:

>    >     template<class ValueType>
>    >       any& operator=(ValueType&& rhs);

>    > > -7- Let `T` be equal to `decay_t<ValueType>`.

>    > > -8- Requires: `T` shall satisfy the `CopyConstructible` requirements. If `is_copy_constructible_v<T>` is `false`, the program is ill-formed.

>    > > […]

>    > > -11- Remarks: This operator shall not participate in overload resolution if unless `decay_t<ValueType>` is not the same type as `any` and `is_copy_constructible_v<T>` is `true`.

> 4. Change 22.7.4.4 [any.modifiers] as indicated:

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

>    > > -?- Let `T` be equal to `remove_cv_t<ValueType>`.

>    > > -1- Requires: `T` shall satisfy the `CopyConstructible` requirements `is_constructible_v<T, Args...>` is `true`.

>    > > […]

>    > > -5- Remarks: If an exception is thrown during the call to `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 unless `is_reference_v<T>` is `false`, `is_array_v<T>` is `false`, `is_function_v<T>` is `false`, `is_copy_constructible_v<T>` is `true` and `is_constructible_v<T, Args...>` is `true`.

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

>    > > -?- Let `T` be equal to `remove_cv_t<ValueType>`.

>    > > -?- Requires: `T` shall satisfy the `CopyConstructible` requirements.

>    > > -6- Effects: […]

>    > > […]

>    > > -9- Remarks: If an exception is thrown during the call to `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 unless `is_reference_v<T>` is `false`, `is_array_v<T>` is `false`, `is_function_v<T>` is `false`, `is_copy_constructible_v<T>` is `true` and `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`.

[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:

1. It strikes the Requires-clauses and does not add `CopyConstructible` to the Requires-clauses.

   Rationale: `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.

2. 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`.

   Rationale:

   1. `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

   2. 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.

> 1. Change 22.7.4 [any.class], class `any` synopsis, as indicated:

>    >     class any {
>    >     public:
>    >       […]
>    >       template <class TValueType, class... Args>
>    >         explicit any(in_place_type_t<TValueType>, Args&&...);
>    >       template <class TValueType, class U, class... Args>
>    >         explicit any(in_place_type_t<TValueType>, initializer_list<U>, Args&&...);

>    >       […]
>    >       template <class TValueType, class... Args>
>    >         void emplace(Args&& ...);
>    >       template <class TValueType, class U, class... Args>
>    >         void emplace(initializer_list<U>, Args&&...);
>    >       […]
>    >     };

> 2. Change 22.7.4.2 [any.cons] as indicated:

>    >     template<class ValueType>
>    >       any(ValueType&& value);

>    > > -6- Let `T` be equal to `decay_t<ValueType>`.

>    > > -7- Requires: `T` shall satisfy the `CopyConstructible` requirements. If `is_copy_constructible_v<T>` is `false`, the program is ill-formed.

>    > > […]

>    > > -9- Remarks: This constructor shall not participate in overload resolution if unless `decay_t<ValueType>` is not the same type as `any` and `is_copy_constructible_v<T>` is `true`.

>    >     template <class TValueType, class... Args>
>    >       explicit any(in_place_type_t<TValueType>, Args&&... args);

>    > > -?- Let `T` be equal to `decay_t<ValueType>`.

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

>    > > […]

>    > > -?- Remarks: This constructor shall not participate in overload resolution unless `is_copy_constructible_v<T>` is `true` and `is_constructible_v<T, Args...>` is `true`.

>    >     template <class TValueType, class U, class... Args>
>    >       explicit any(in_place_type_t<TValueType>, initializer_list<U> il, Args&&... args);

>    > > -?- Let `T` be equal to `decay_t<ValueType>`.

>    > > -15- Requires: `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`.

>    > > […]

>    > > -19- Remarks: The function shall not participate in overload resolution unless `is_copy_constructible_v<T>` is `true` and `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`.

> 3. Change 22.7.4.3 [any.assign] as indicated:

>    >     template<class ValueType>
>    >       any& operator=(ValueType&& rhs);

>    > > -7- Let `T` be equal to `decay_t<ValueType>`.

>    > > -8- Requires: `T` shall satisfy the `CopyConstructible` requirements. If `is_copy_constructible_v<T>` is `false`, the program is ill-formed.

>    > > […]

>    > > -11- Remarks: This operator shall not participate in overload resolution if unless `decay_t<ValueType>` is not the same type as `any` and `is_copy_constructible_v<T>` is `true`.

> 4. Change 22.7.4.4 [any.modifiers] as indicated:

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

>    > > -?- Let `T` be equal to `decay_t<ValueType>`.

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

>    > > […]

>    > > -5- Remarks: If an exception is thrown during the call to `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 unless `is_copy_constructible_v<T>` is `true` and `is_constructible_v<T, Args...>` is `true`.

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

>    > > -?- Let `T` be equal to `decay_t<ValueType>`.

>    > > -6- Effects: […]

>    > > […]

>    > > -9- Remarks: If an exception is thrown during the call to `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 unless `is_copy_constructible_v<T>` is `true` and `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`.

[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.

1. Change 22.7.4 [any.class], class `any` synopsis, as indicated:

   >     class any {
   >     public:
   >       […]
   >       template <class TValueType, class... Args>
   >         explicit any(in_place_type_t<TValueType>, Args&&...);
   >       template <class TValueType, class U, class... Args>
   >         explicit any(in_place_type_t<TValueType>, initializer_list<U>, Args&&...);

   >       […]
   >       template <class TValueType, class... Args>
   >         void emplace(Args&& ...);
   >       template <class TValueType, class U, class... Args>
   >         void emplace(initializer_list<U>, Args&&...);
   >       […]
   >     };

2. Change 22.7.4.2 [any.cons] as indicated:

   >     template<class ValueType>
   >       any(ValueType&& value);

   > > -6- Let `T` be `decay_t<ValueType>`.

   > > -7- Requires: `T` shall satisfy the `CopyConstructible` requirements. If `is_copy_constructible_v<T>` is `false`, the program is ill-formed.

   > > […]

   > > -9- Remarks: This constructor shall not participate in overload resolution if unless `Tdecay_t<ValueType>` is not the same type as `any` and `is_copy_constructible_v<T>` is `true`.

   >     template <class TValueType, class... Args>
   >       explicit any(in_place_type_t<TValueType>, Args&&... args);

   > > -?- Let `T` be `decay_t<ValueType>`.

   > > -11- Requires: `T` shall satisfy the `CopyConstructible` requirements `is_constructible_v<T, Args...>` is `true`.

   > > […]

   > > -?- Remarks: This constructor shall not participate in overload resolution unless `is_copy_constructible_v<T>` is `true` and `is_constructible_v<T, Args...>` is `true`.

   >     template <class TValueType, class U, class... Args>
   >       explicit any(in_place_type_t<TValueType>, initializer_list<U> il, Args&&... args);

   > > -?- Let `T` be `decay_t<ValueType>`.

   > > -15- Requires: `T` shall satisfy the `CopyConstructible` requirements `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`.

   > > […]

   > > -19- Remarks: The function shall not participate in overload resolution unless `is_copy_constructible_v<T>` is `true` and `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`.

3. Change 22.7.4.3 [any.assign] as indicated:

   >     template<class ValueType>
   >       any& operator=(ValueType&& rhs);

   > > -7- Let `T` be `decay_t<ValueType>`.

   > > -8- Requires: `T` shall satisfy the `CopyConstructible` requirements. If `is_copy_constructible_v<T>` is `false`, the program is ill-formed.

   > > […]

   > > -11- Remarks: This operator shall not participate in overload resolution if unless `Tdecay_t<ValueType>` is not the same type as `any` and `is_copy_constructible_v<T>` is `true`.

4. Change 22.7.4.4 [any.modifiers] as indicated:

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

   > > -?- Let `T` be `decay_t<ValueType>`.

   > > -1- Requires: `T` shall satisfy the `CopyConstructible` requirements `is_constructible_v<T, Args...>` is `true`.

   > > […]

   > > -5- Remarks: If an exception is thrown during the call to `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 unless `is_copy_constructible_v<T>` is `true` and `is_constructible_v<T, Args...>` is `true`.

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

   > > -?- Let `T` be `decay_t<ValueType>`.

   > > -?- Requires: `T` shall satisfy the `CopyConstructible` requirements.

   > > -6- Effects: […]

   > > […]

   > > -9- Remarks: If an exception is thrown during the call to `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 unless `is_copy_constructible_v<T>` is `true` and `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`.