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(i) can also take advantage of the definition of a referenceable type.

If the proposed resolution for LWG issue 2101(i) 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.