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

### 882. `duration` non-member arithmetic requirements

Section: 29.5.6 [time.duration.nonmember] Status: CD1 Submitter: Howard Hinnant Opened: 2008-09-08 Last modified: 2016-01-28

Priority: Not Prioritized

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

View all issues with CD1 status.

Discussion:

N2661 specified the following requirements for the non-member `duration` arithmetic:

>     template <class Rep1, class Period, class Rep2>
>       duration<typename common_type<Rep1, Rep2>::type, Period>
>       operator*(const duration<Rep1, Period>& d, const Rep2& s);

> > Requires: Let `CR` represent the `common_type` of `Rep1` and `Rep2`. Both `Rep1` and `Rep2` shall be implicitly convertible to CR, diagnostic required.

>     template <class Rep1, class Period, class Rep2>
>       duration<typename common_type<Rep1, Rep2>::type, Period>
>       operator*(const Rep1& s, const duration<Rep2, Period>& d);

> > Requires: Let `CR` represent the `common_type` of `Rep1` and `Rep2`. Both `Rep1` and `Rep2` shall be implicitly convertible to `CR`, diagnostic required.

>     template <class Rep1, class Period, class Rep2>
>       duration<typename common_type<Rep1, Rep2>::type, Period>
>       operator/(const duration<Rep1, Period>& d, const Rep2& s);

> > Requires: Let `CR` represent the `common_type` of `Rep1` and `Rep2`. Both `Rep1` and `Rep2` shall be implicitly convertible to `CR`, and `Rep2` shall not be an instantiation of `duration`, diagnostic required.

During transcription into the working paper, the requirements clauses on these three functions was changed to:

> Requires: `CR(Rep1, Rep2)` shall exist. Diagnostic required.

This is a non editorial change with respect to N2661 as user written representations which are used in `duration` need not be implicitly convertible to or from arithmetic types in order to interoperate with `duration`s based on arithmetic types. An explicit conversion will do fine for most expressions as long as there exists a `common_type` specialization relating the user written representation and the arithmetic type. For example:

>     class saturate
>     {
>     public:
>       explicit saturate(long long i);
>       ...
>     };

>     namespace std {

>     template <>
>     struct common_type<saturate, long long>
>     {
>         typedef saturate type;
>     };

>     template <>
>     struct common_type<long long, saturate>
>     {
>         typedef saturate type;
>     };

>     }  // std

>     millisecond ms(3);  // integral-based duration
>     duration<saturate, milli> my_ms = ms;  // ok, even with explicit conversions
>     my_ms = my_ms + ms;                    // ok, even with explicit conversions

However, when dealing with multiplication of a duration and its representation, implicit convertibility is required between the rhs and the lhs's representation for the member `*=` operator:

>     template <class Rep, class Period = ratio<1>>
>     class duration {
>     public:
>        ...
>        duration& operator*=(const rep& rhs);
>        ...
>     };
>     ...
>     ms *= 2;               // ok, 2 is implicitly convertible to long long
>     my_ms *= saturate(2);  // ok, rhs is lhs's representation
>     my_ms *= 2;            // error, 2 is not implicitly convertible to saturate

The last line does not (and should not) compile. And we want non-member multiplication to have the same behavior as member arithmetic:

>     my_ms = my_ms * saturate(2);  // ok, rhs is lhs's representation
>     my_ms = my_ms * 2;            // should be error, 2 is not implicitly convertible to saturate

The requirements clauses of N2661 make the last line an error as expected. However the latest working draft at this time (N2723) allows the last line to compile.

All that being said, there does appear to be an error in these requirements clauses as specified by N2661.

> Requires: ... Both `Rep1` and `Rep2` shall be implicitly convertible to CR, diagnostic required.

It is not necessary for both `Rep`s to be implicitly convertible to the `CR`. It is only necessary for the rhs `Rep` to be implicitly convertible to the `CR`. The `Rep` within the `duration` should be allowed to only be explicitly convertible to the `CR`. The explicit-conversion-requirement is covered under 29.5.8 [time.duration.cast].

Proposed resolution:

Change the requirements clauses under 29.5.6 [time.duration.nonmember]:

>     template <class Rep1, class Period, class Rep2>
>       duration<typename common_type<Rep1, Rep2>::type, Period>
>       operator*(const duration<Rep1, Period>& d, const Rep2& s);

> > Requires: `CR(Rep1, Rep2)` shall exist. `Rep2` shall be implicitly convertible to `CR(Rep1, Rep2)`. Diagnostic required.

>     template <class Rep1, class Period, class Rep2>
>       duration<typename common_type<Rep1, Rep2>::type, Period>
>       operator*(const Rep1& s, const duration<Rep2, Period>& d);

> > Requires d behavior: `CR(Rep1, Rep2)` shall exist. `Rep1` shall be implicitly convertible to `CR(Rep1, Rep2)`. Diagnostic required.

>     template <class Rep1, class Period, class Rep2>
>       duration<typename common_type<Rep1, Rep2>::type, Period>
>       operator/(const duration<Rep1, Period>& d, const Rep2& s);

> > Requires: `CR(Rep1, Rep2)` shall exist `Rep2` shall be implicitly convertible to `CR(Rep1, Rep2)` and `Rep2` shall not be an instantiation of `duration`. Diagnostic required.