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.

### 3050. Conversion specification problem in `chrono::duration` constructor

Section: 29.5.2 [time.duration.cons], 29.5.6 [time.duration.nonmember] Status: C++20 Submitter: Barry Revzin Opened: 2018-01-22 Last modified: 2021-02-25

Priority: 3

View all other issues in [time.duration.cons].

View all issues with C++20 status.

Discussion:

The converting constructor in `std::chrono::duration` is currently specified as (29.5.2 [time.duration.cons] p1):

>     template<class Rep2>
>       constexpr explicit duration(const Rep2& r);

> > Remarks: This constructor shall not participate in overload resolution unless `Rep2` is implicitly convertible to `rep` and […]

But the parameter is of type `Rep2 const`, so we should check that `Rep2 const` is implicitly convertible to `rep`, not just `Rep2`. This means that for a type like:

>     struct X { operator int64_t() /* not const */; };

`std::is_constructible_v<std::chrono::seconds, X>` is `true`, but actual construction will fail to compile.

Further analysis of sub-clause 29.5 [time.duration] revealed similar specification problems in some other functions.

[2018-06 Rapperswil Thursday issues processing]

P3; Status to Open

[2018-11 San Diego Thursday night issue processing]

Jonathan to provide updated wording; the underlying text has changed.

[2018-12-05 Jonathan provides new wording]

In San Diego Geoff noticed that the current WP does not use `CR`. Jonathan provides new wording consistent with the editorial changes that removed `CR`.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4713.

> 1. Modify 29.5.2 [time.duration.cons] as indicated:

>    >     template<class Rep2>
>    >       constexpr explicit duration(const Rep2& r);

>    > > -1- Remarks: This constructor shall not participate in overload resolution unless `is_convertible_v<const Rep2&, rep>` is `true` `Rep2` is implicitly convertible to `rep` and

>    > > 1. (1.1) — `treat_as_floating_point_v<rep>` is `true` or

>    > > 2. (1.2) — `treat_as_floating_point_v<Rep2>` is `false`.

>    > > […]

>    > > -2- Effects: Constructs an object of type `duration`.

>    > > -3- Postconditions: `count() == static_cast<rep>(r)`.

> 2. Modify 29.5.6 [time.duration.nonmember] as indicated:

>    >     template<class Rep1, class Period, class Rep2>
>    >       constexpr duration<common_type_t<Rep1, Rep2>, Period>
>    >         operator*(const duration<Rep1, Period>& d, const Rep2& s);

>    > > -4- Remarks: This operator shall not participate in overload resolution unless `is_convertible_v<const Rep2&, CR(Rep1, Rep2)>` is `true` `Rep2` is implicitly convertible to `CR(Rep1, Rep2)`.

>    > > […]

>    >     template<class Rep1, class Rep2, class Period>
>    >       constexpr duration<common_type_t<Rep1, Rep2>, Period>
>    >         operator*(const Rep1& s, const duration<Rep2, Period>& d);

>    > > -6- Remarks: This operator shall not participate in overload resolution unless `is_convertible_v<const Rep1&, CR(Rep1, Rep2)>` is `true` `Rep1` is implicitly convertible to `CR(Rep1, Rep2)`.

>    > > […]

>    >     template<class Rep1, class Period, class Rep2>
>    >       constexpr duration<common_type_t<Rep1, Rep2>, Period>
>    >         operator/(const duration<Rep1, Period>& d, const Rep2& s);

>    > > -8- Remarks: This operator shall not participate in overload resolution unless `is_convertible_v<const Rep2&, CR(Rep1, Rep2)>` is `true` `Rep2` is implicitly convertible to `CR(Rep1, Rep2)` and `Rep2` is not a specialization of `duration`.

>    > […]

>    >     template<class Rep1, class Period, class Rep2>
>    >       constexpr duration<common_type_t<Rep1, Rep2>, Period>
>    >         operator%(const duration<Rep1, Period>& d, const Rep2& s);

>    > > -11- Remarks: This operator shall not participate in overload resolution unless `is_convertible_v<const Rep2&, CR(Rep1, Rep2)>` is `true` `Rep2` is implicitly convertible to `CR(Rep1, Rep2)` and `Rep2` is not a specialization of `duration`.

>    > > […]

Previous resolution [SUPERSEDED]:

> This wording is relative to N4791.

> 1. Modify 29.5.2 [time.duration.cons] as indicated:

>    >     template<class Rep2>
>    >       constexpr explicit duration(const Rep2& r);

>    > > -1- Remarks: This constructor shall not participate in overload resolution unless `is_convertible_v<const Rep2&, rep>` is `true` `Rep2` is implicitly convertible to `rep` and

>    > > 1. (1.1) — `treat_as_floating_point_v<rep>` is `true` or

>    > > 2. (1.2) — `treat_as_floating_point_v<Rep2>` is `false`.

>    > > […]

>    > > -2- Effects: Constructs an object of type `duration`.

>    > > -3- Postconditions: `count() == static_cast<rep>(r)`.

> 2. Modify 29.5.6 [time.duration.nonmember] as indicated:

>    >     template<class Rep1, class Period, class Rep2>
>    >       constexpr duration<common_type_t<Rep1, Rep2>, Period>
>    >         operator*(const duration<Rep1, Period>& d, const Rep2& s);

>    > > -4- Remarks: This operator shall not participate in overload resolution unless `is_convertible_v<const Rep2&, common_type_t<Rep1, Rep2>>` is `true` `Rep2` is implicitly convertible to `common_type_t<Rep1, Rep2>`.

>    > > […]

>    >     template<class Rep1, class Rep2, class Period>
>    >       constexpr duration<common_type_t<Rep1, Rep2>, Period>
>    >         operator*(const Rep1& s, const duration<Rep2, Period>& d);

>    > > -6- Remarks: This operator shall not participate in overload resolution unless `is_convertible_v<const Rep1&, common_type_t<Rep1, Rep2>>` is `true` `Rep1` is implicitly convertible to `common_type_t<Rep1, Rep2>`.

>    > > […]

>    >     template<class Rep1, class Period, class Rep2>
>    >       constexpr duration<common_type_t<Rep1, Rep2>, Period>
>    >         operator/(const duration<Rep1, Period>& d, const Rep2& s);

>    > > -8- Remarks: This operator shall not participate in overload resolution unless `is_convertible_v<const Rep2&, common_type_t<Rep1, Rep2>>` is `true` `Rep2` is implicitly convertible to `common_type_t<Rep1, Rep2>` and `Rep2` is not a specialization of `duration`.

>    > […]

>    >     template<class Rep1, class Period, class Rep2>
>    >       constexpr duration<common_type_t<Rep1, Rep2>, Period>
>    >         operator%(const duration<Rep1, Period>& d, const Rep2& s);

>    > > -11- Remarks: This operator shall not participate in overload resolution unless `is_convertible_v<const Rep2&, common_type_t<Rep1, Rep2>>` is `true` `Rep2` is implicitly convertible to `common_type_t<Rep1, Rep2>` and `Rep2` is not a specialization of `duration`.

>    > > […]

[2020-02-13, Prague]

Rebase to most recent working draft

[2020-02 Status to Immediate on Thursday night in Prague.]

Proposed resolution:

This wording is relative to N4849.

1. Modify 29.5.2 [time.duration.cons] as indicated:

   >     template<class Rep2>
   >       constexpr explicit duration(const Rep2& r);

   > > -1- Constraints: `is_convertible_v<const Rep2&, rep>` is `true` and

   > > 1. (1.1) — `treat_as_floating_point_v<rep>` is `true` or

   > > 2. (1.2) — `treat_as_floating_point_v<Rep2>` is `false`.

   > > […]

   > > -2- Postconditions: `count() == static_cast<rep>(r)`.

2. Modify 29.5.6 [time.duration.nonmember] as indicated:

   >     template<class Rep1, class Period, class Rep2>
   >       constexpr duration<common_type_t<Rep1, Rep2>, Period>
   >         operator*(const duration<Rep1, Period>& d, const Rep2& s);

   > > -4- Constraints: `is_convertible_v<const Rep2&, common_type_t<Rep1, Rep2>>` is `true`.

   > > […]

   >     template<class Rep1, class Rep2, class Period>
   >       constexpr duration<common_type_t<Rep1, Rep2>, Period>
   >         operator*(const Rep1& s, const duration<Rep2, Period>& d);

   > > -6- Constraints: `is_convertible_v<const Rep1&, common_type_t<Rep1, Rep2>>` is `true`.

   > > […]

   >     template<class Rep1, class Period, class Rep2>
   >       constexpr duration<common_type_t<Rep1, Rep2>, Period>
   >         operator/(const duration<Rep1, Period>& d, const Rep2& s);

   > > -8- Constraints: `is_convertible_v<const Rep2&, common_type_t<Rep1, Rep2>>` is `true` and `Rep2` is not a specialization of `duration`.

   > […]

   >     template<class Rep1, class Period, class Rep2>
   >       constexpr duration<common_type_t<Rep1, Rep2>, Period>
   >         operator%(const duration<Rep1, Period>& d, const Rep2& s);

   > > -12- Constraints: `is_convertible_v<const Rep2&, common_type_t<Rep1, Rep2>>` is `true` and `Rep2` is not a specialization of `duration`.

   > > […]