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.

### 2040. Missing type traits related to `is_convertible`

Section: 20.15 [meta] Status: Resolved Submitter: Daniel Krügler Opened: 2011-03-03 Last modified: 2020-09-06

Priority: Not Prioritized

View other active issues in [meta].

View all other issues in [meta].

View all issues with Resolved status.

Discussion:

When n3142 was suggested, it concentrated on constructions, assignments, and destructions, but overlooked to complement the single remaining compiler-support trait

>     template <class From, class To> struct is_convertible;

with the no-throw and triviality related aspects as it had been done with the other expression-based traits. Specifically, the current specification misses to add the following traits:

>     template <class From, class To> struct is_nothrow_convertible;
>     template <class From, class To> struct is_trivially_convertible;

In particular the lack of `is_nothrow_convertible` is severely restricting. This was recently recognized when the proposal for `decay_copy` was prepared by n3255. There does not exist a portable means to define the correct conditional `noexcept` specification for the `decay_copy` function template, which is declared as:

>     template <class T>
>     typename decay<T>::type decay_copy(T&& v) noexcept(???);

The semantics of `decay_copy` bases on an implicit conversion which again influences the overload set of functions that are viable here. In most circumstances this will have the same effect as comparing against the trait `std::is_nothrow_move_constructible`, but there is no guarantee for that being the right answer. It is possible to construct examples, where this would lead to the false result, e.g.

>     struct S {
>       S(const S&) noexcept(false);

>       template<class T>
>       explicit S(T&&) noexcept(true);
>     };

`std::is_nothrow_move_constructible` will properly honor the explicit template constructor because of the direct-initialization context which is part of the `std::is_constructible` definition and will in this case select it, such that `std::is_nothrow_move_constructible<S>::value == true`, but if we had the traits `is_nothrow_convertible`, `is_nothrow_convertible<S, S>::value` would evaluate to `false`, because it would use the copy-initialization context that is part of the `is_convertible` definition, excluding any explicit constructors and giving the opposite result.

The `decay_copy` example is surely not one of the most convincing examples, but `is_nothrow_convertible` has several use-cases, and can e.g. be used to express whether calling the following implicit conversion function could throw an exception or not:

>     template<class T, class U>
>     T implicit_cast(U&& u) noexcept(is_nothrow_convertible<U, T>::value)
>     {
>       return std::forward<U>(u);
>     }

Therefore I suggest to add the missing trait `is_nothrow_convertible` and for completeness also the missing trait `is_trivially_convertible` to 20.15 [meta].

[2011-03-24 Madrid meeting]

Daniel K: This is a new feature so out of scope.

Pablo: Any objections to moving 2040 to Open?

No objections.

[Bloomington, 2011]

Move to NAD Future, this would be an extension to existing functionality.

[LEWG, Kona 2017]

Fallen through the cracks since 2011, but we should discuss it. Alisdair points out that triviality is about replacing operations with `memcpy`, so be sure this is false for `int`->`float`.

[Rapperswil, 2018]

Resolved by the adoption of p0758r1.

Proposed resolution:

1. Ammend the following declarations to the header `<type_traits>` synopsis in 20.15.3 [meta.type.synop]:

   >     namespace std {
   >       …
   >       // 20.9.6, type relations:
   >       template <class T, class U> struct is_same;
   >       template <class Base, class Derived> struct is_base_of;
   >       template <class From, class To> struct is_convertible;
   >       template <class From, class To> struct is_trivially_convertible;
   >       template <class From, class To> struct is_nothrow_convertible;

   >       …
   >     }

2. Modify Table 51 — "Type relationship predicates" as indicated. The removal of the remaining traces of the trait `is_explicitly_convertible` is an editorial step, it was removed by n3047:

   > Table 51 — Type relationship predicates
   > Template | Condition | Comments
   > --- | --- | ---
   > …
   > `template <class From, class To> struct is_convertible;` | see below | `From` and `To` shall be complete types, arrays of unknown bound, or (possibly cv-qualified) `void` types.
   > `template <class From, class To> struct is_explicitly_convertible;` | `is_constructible<To, From>::value` | a synonym for a two-argument version of `is_constructible`. An implementation may define it as an alias template.
   > `template <class From, class To> struct is_trivially_convertible;` | `is_convertible<From, To>::value` is `true` and the conversion, as defined by `is_convertible`, is known to call no operation that is not trivial ([basic.types], [special]). | `From` and `To` shall be complete types, arrays of unknown bound, or (possibly cv-qualified) `void` types.
   > `template <class From, class To> struct is_nothrow_convertible;` | `is_convertible<From, To>::value` is `true` and the conversion, as defined by `is_convertible`, is known not to throw any exceptions ([expr.unary.noexcept]). | `From` and `To` shall be complete types, arrays of unknown bound, or (possibly cv-qualified) `void` types.
   > …