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

### 3194. `ConvertibleTo` prose does not match code

Section: 18.4.4 [concept.convertible] Status: C++20 Submitter: Hubert Tong Opened: 2019-03-05 Last modified: 2021-02-25

Priority: 1

View other active issues in [concept.convertible].

View all other issues in [concept.convertible].

View all issues with C++20 status.

Discussion:

The prose in N4800 subclause [concept.convertibleto] indicates that the requirement is for an expression of a particular type and value category to be both implicitly and explicitly convertible to some other type. However, for a type

>     struct A { A(const A&) = delete; };

`ConvertibleTo<const A, A>` would be `false` despite the following being okay:

>     const A f();

>     A test() {
>       static_cast<A>(f());
>       return f();
>     }

[2019-03-15 Priority set to 1 after reflector discussion]

[2019-07-14 Tim adds PR based on discussion in 2019-07-09 LWG telecon]

Previous resolution [SUPERSEDED]:

> This wording is relative to N4820, and also resolves LWG 3151.

> 1. Modify [concept.convertibleto] as indicated:

>    > -1- The `ConvertibleTo` concept requires an a glvalue expression of a particular type and value category to be both implicitly and explicitly convertible to some other type. The implicit and explicit conversions are required to produce equal results.

>    >     template<class From, class To>
>    >       concept ConvertibleTo =
>    >         is_convertible_v<From, To> &&
>    >         requires(add_rvalue_reference_t<From> (&f)()) {
>    >           static_cast<To>(f());
>    >         };

>    > > -2- Let `test` be the invented function:

>    > > >     To test(add_rvalue_reference_t<From> (&f)()) {
>    > > >       return f();
>    > > >     }

>    > > for some types `From` and `To`, and let `f` be a function with no arguments and return type `add_rvalue_reference_t<From>` such that `f()` is equality-preserving. `From` and `To` model `ConvertibleTo<From, To>` only if:

>    > > 1. (2.1) — `To` is not an object or reference-to-object type, or `static_cast<To>(f())` is equal to `test(f)`.

>    > > 2. (2.2) — `add_rvalue_reference_t<From>` is not a reference-to-object type, or

>    > >    1. (2.2.1) — If `add_rvalue_reference_t<From>` is an rvalue reference to a non const-qualified type, the resulting state of the object referenced by `f()` after either above expression is valid but unspecified (16.4.6.15 [lib.types.movedfrom]).

>    > >    2. (2.2.2) — Otherwise, the object referred to by `f()` is not modified by either above expression.

[2019-09-23; Daniel adjusts wording to working draft changes]

Due to the concept renaming caused by P1754R1 the proposed wording is outdated and needs adjustments.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4830, and also resolves LWG 3151.

> 1. Modify 18.4.4 [concept.convertible] as indicated:

>    > -1- The `convertible_to` concept requires an a glvalue expression of a particular type and value category to be both implicitly and explicitly convertible to some other type. The implicit and explicit conversions are required to produce equal results.

>    >     template<class From, class To>
>    >       concept convertible_to =
>    >         is_convertible_v<From, To> &&
>    >         requires(add_rvalue_reference_t<From> (&f)()) {
>    >           static_cast<To>(f());
>    >         };

>    > > -2- Let `test` be the invented function:

>    > > >     To test(add_rvalue_reference_t<From> (&f)()) {
>    > > >       return f();
>    > > >     }

>    > > for some types `From` and `To`, and let `f` be a function with no arguments and return type `add_rvalue_reference_t<From>` such that `f()` is equality-preserving. `From` and `To` model `convertible_to<From, To>` only if:

>    > > 1. (2.1) — `To` is not an object or reference-to-object type, or `static_cast<To>(f())` is equal to `test(f)`.

>    > > 2. (2.2) — `add_rvalue_reference_t<From>` is not a reference-to-object type, or

>    > >    1. (2.2.1) — If `add_rvalue_reference_t<From>` is an rvalue reference to a non const-qualified type, the resulting state of the object referenced by `f()` after either above expression is valid but unspecified (16.4.6.15 [lib.types.movedfrom]).

>    > >    2. (2.2.2) — Otherwise, the object referred to by `f()` is not modified by either above expression.

[2019-11-06 Tim updates PR based on discussion in Belfast LWG evening session]

"glvalue" is incorrect because we want to allow testing `convertible_to<void, void>`. It's also less than clear how the "expression" and "a particular type" in the first sentence correspond to the parameters of the concept.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4835, and also resolves LWG 3151.

> 1. Modify 18.4.4 [concept.convertible] as indicated:

>    > -1- The `convertible_to` concept for types `From` and `To` requires an expression `E` such that `decltype((E))` is `add_rvalue_reference_t<From>` of a particular type and value category to be both implicitly and explicitly convertible to some other type `To`. The implicit and explicit conversions are required to produce equal results.

>    >     template<class From, class To>
>    >       concept convertible_to =
>    >         is_convertible_v<From, To> &&
>    >         requires(add_rvalue_reference_t<From> (&f)()) {
>    >           static_cast<To>(f());
>    >         };

>    > > -2- Let `FromR` be `add_rvalue_reference_t<From>` and `test` be the invented function:

>    > > >     To test(FromR (&f)()) {
>    > > >       return f();
>    > > >     }

>    > > for some types `From` and `To`, and let `f` be a function with no arguments and return type `FromR` such that `f()` is equality-preserving. `From` and `To` model `convertible_to<From, To>` only if:

>    > > 1. (2.1) — `To` is not an object or reference-to-object type, or `static_cast<To>(f())` is equal to `test(f)`.

>    > > 2. (2.2) — `FromR` is not a reference-to-object type, or

>    > >    1. (2.2.1) — If `FromR` is an rvalue reference to a non const-qualified type, the resulting state of the object referenced by `f()` after either above expression is valid but unspecified (16.4.6.15 [lib.types.movedfrom]).

>    > >    2. (2.2.2) — Otherwise, the object referred to by `f()` is not modified by either above expression.

[2019-11-09 Tim rephrased first sentence based on discussion in Belfast LWG Saturday session]

[Status to Tentatively ready after Belfast LWG Saturday session]

Proposed resolution:

This wording is relative to N4835, and also resolves LWG 3151.

1. Modify 18.4.4 [concept.convertible] as indicated:

   > -1- Given types `From` and `To` and an expression `E` such that `decltype((E))` is `add_rvalue_reference_t<From>`, `convertible_to<From, To>` The `convertible_to` concept requires `E` an expression of a particular type and value category to be both implicitly and explicitly convertible to some other type `To`. The implicit and explicit conversions are required to produce equal results.

   >     template<class From, class To>
   >       concept convertible_to =
   >         is_convertible_v<From, To> &&
   >         requires(add_rvalue_reference_t<From> (&f)()) {
   >           static_cast<To>(f());
   >         };

   > > -2- Let `FromR` be `add_rvalue_reference_t<From>` and `test` be the invented function:

   > > >     To test(FromR (&f)()) {
   > > >       return f();
   > > >     }

   > > for some types `From` and `To`, and let `f` be a function with no arguments and return type `FromR` such that `f()` is equality-preserving. `From` and `To` model `convertible_to<From, To>` only if:

   > > 1. (2.1) — `To` is not an object or reference-to-object type, or `static_cast<To>(f())` is equal to `test(f)`.

   > > 2. (2.2) — `FromR` is not a reference-to-object type, or

   > >    1. (2.2.1) — If `FromR` is an rvalue reference to a non const-qualified type, the resulting state of the object referenced by `f()` after either above expression is valid but unspecified (16.4.6.15 [lib.types.movedfrom]).

   > >    2. (2.2.2) — Otherwise, the object referred to by `f()` is not modified by either above expression.