LWG 2939 suggests that the the preconditions of the type traits need reevaluation.
This issue focuses specifically on is_assignable and, by extension, its variants:
- is_copy_assignable<T>, equivalent to is_assignable<T&, const T&>,
- is_move_assignable<T>, equivalent to is_assignable<T&, T>,
- is_trivially_assignable<T, U>, equivalent to is_assignable<T, U> &&
/* magic */,
- is_trivially_copy_assignable<T>, equivalent to is_assignable<T&, const T&> &&
/* magic */,
- is_trivially_move_assignable<T>, equivalent to is_assignable<T&, T> &&
/* magic */,
- is_nothrow_assignable<T, U>, equivalent to is_assignable<T, U> &&
noexcept(declval<T>() = declval<U>()),
- is_nothrow_copy_assignable<T>, equivalent to is_assignable<T&, const T&> &&
noexcept(declval<T&>() = declval<const T&>()),
- is_nothrow_move_assignable<T>, equivalent to is_assignable<T&, T> &&
noexcept(declval<T&>() = declval<T>()), and
We note a discrepancy: is_copy_assignable<T> requires T to be a complete type, but the
equivalent form is_assignable<T&, const T&> does not. The requirement for
is_copy_assignable<T> seems sensible, since there's no way to determine whether or not the assignment
declval<T&>() = declval<const T&>() is well-formed when T is incomplete.
It seems that the same argument should apply to all of the above "assignable" traits, and that they must require that
the referent type is complete when given a reference type parameter to be implementable.