This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++14 status.

### 2196. Specification of `is_*[copy/move]_[constructible/assignable]` unclear for non-referencable types

Section: 21.3.5.4 [meta.unary.prop] Status: C++14 Submitter: Daniel Krügler Opened: 2012-10-06 Last modified: 2016-01-28

Priority: Not Prioritized

View other active issues in [meta.unary.prop].

View all other issues in [meta.unary.prop].

View all issues with C++14 status.

Discussion:

The pre-conditions for the type `is_copy_constructible` allow for template argument types were the language forbids forming a reference, namely `void` types and function types that have cv-qualifiers or a ref-qualifier.

But the current wording in Table 49 defining the predicate condition,

> `is_constructible<T, const T&>::value` is `true`.

leaves it open whether such argument types would (a) create a well-formed instantiation of the trait template or if so (b) what the outcome of the trait evaluation would be, as an example consider `std::is_copy_constructible<void>`.

Current implementations differ, e.g. gcc accepts the instantiation and returns a false result, VS 2012 also accepts the instantiation but returns true.

I would suggest that the wording clarifies that the instantiation would be valid for these types and I also would strongly prefer the outcome that the trait would always return false for these types. The latter seems rather natural to me, because there is no way to define a variable of `void` type or of function type at all, so it would be surprising to return a positive result for copy or move construction if no other construction could succeed. It is also not possible to assign to a any of these values (because there is no way to form lvalues of them), so the same argumentation can be applied to the `is_copy/move_assignable` traits as well.

To reduce the amount of wording changes and repetitions, I suggest to define the term referenceable type in sub-clause [definitions] or alternatively in the core language to describe types to which references can be created via a typedef name. This definition corresponds to what the support concept `ReferentType` intended to describe during concept time.

In addition, LWG issue 2101 can also take advantage of the definition of a referenceable type.

If the proposed resolution for LWG issue 2101 would be accepted, there is an alternative solution possible with the same effects. Now we would be able to use the now always well-formed instantiation of `std::add_lvalue_reference` to modify the current definition of `is_copy_constructible` to

> `is_constructible<T,
> typename add_lvalue_reference<
> typename add_const<T>::type>::type>::value` is true.

and similar changes for the other affected traits.

[2012-10 Portland: Move to Open]

Referencable-type should be defined as "something that can be bound into a reference" or similar, rather than a list of types where that is true today. We can then provide the list of known types that cannot be bound as examples that do not qualify in a note.

Otherwise we are happy with the wording. AJM to redraft the definition and move to Review.

[2013-04-18, Bristol]

Proposed resolution:

This wording is relative to N3376.

1. Add the following new definition to [definitions] as indicated:

   referenceable type [defns.referenceable]

   > An object type, a function type that does not have cv-qualifiers or a ref-qualifier, or a reference type. [Note: The term describes a type to which a reference can be created, including reference types. — end note]

2. Change Table 49 as indicated:

   Table 49 — Type property predicates
   Template | Condition | Preconditions
   --- | --- | ---
   `template <class T>` `struct is_copy_constructible;` | For a referenceable type `T`, the same result as `is_constructible<T,` `const T&>::value` is true, otherwise false. | `T` shall be a complete type, (possibly cv-qualified) `void`, or an array of unknown bound.
   `template <class T>` `struct is_move_constructible;` | For a referenceable type `T`, the same result as `is_constructible<T,` `T&&>::value` is true, otherwise false. | `T` shall be a complete type, (possibly cv-qualified) `void`, or an array of unknown bound.
   `…`
   `template <class T>` `struct is_copy_assignable;` | For a referenceable type `T`, the same result as `is_assignable<T&,` `const T&>::value` is true, otherwise false. | `T` shall be a complete type, (possibly cv-qualified) `void`, or an array of unknown bound.
   `template <class T>` `struct is_move_assignable;` | For a referenceable type `T`, the same result as `is_assignable<T&,` `T&&>::value` is true, otherwise false. | `T` shall be a complete type, (possibly cv-qualified) `void`, or an array of unknown bound.
   `…`
   `template <class T>` `struct is_trivially_copy_constructible;` | For a referenceable type `T`, the same result as `is_trivially_constructible<T,` `const T&>::value` is true, otherwise false. | `T` shall be a complete type, (possibly cv-qualified) `void`, or an array of unknown bound.
   `template <class T>` `struct is_trivially_move_constructible;` | For a referenceable type `T`, the same result as `is_trivially_constructible<T,` `T&&>::value` is true, otherwise false. | `T` shall be a complete type, (possibly cv-qualified) `void`, or an array of unknown bound.
   `…`
   `template <class T>` `struct is_trivially_copy_assignable;` | For a referenceable type `T`, the same result as `is_trivially_assignable<T&,` `const T&>::value` is true, otherwise false. | `T` shall be a complete type, (possibly cv-qualified) `void`, or an array of unknown bound.
   `template <class T>` `struct is_trivially_move_assignable;` | For a referenceable type `T`, the same result as `is_trivially_assignable<T&,` `T&&>::value` is true, otherwise false. | `T` shall be a complete type, (possibly cv-qualified) `void`, or an array of unknown bound.
   `…`
   `template <class T>` `struct is_nothrow_copy_constructible;` | For a referenceable type `T`, the same result as `is_nothrow_constructible<T,` `const T&>::value` is true, otherwise false. | `T` shall be a complete type, (possibly cv-qualified) `void`, or an array of unknown bound.
   `template <class T>` `struct is_nothrow_move_constructible;` | For a referenceable type `T`, the same result as `is_nothrow_constructible<T,` `T&&>::value` is true, otherwise false. | `T` shall be a complete type, (possibly cv-qualified) `void`, or an array of unknown bound.
   `…`
   `template <class T>` `struct is_nothrow_copy_assignable;` | For a referenceable type `T`, the same result as `is_nothrow_assignable<T&,` `const T&>::value` is true, otherwise false. | `T` shall be a complete type, (possibly cv-qualified) `void`, or an array of unknown bound.
   `template <class T>` `struct is_nothrow_move_assignable;` | For a referenceable type `T`, the same result as `is_nothrow_assignable<T&,` `T&&>::value` is true, otherwise false. | `T` shall be a complete type, (possibly cv-qualified) `void`, or an array of unknown bound.