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

### 2020. Time utility arithmetic `constexpr` functions have invalid effects

Section: 29.5.6 [time.duration.nonmember] Status: C++11 Submitter: Daniel Krügler Opened: 2010-12-06 Last modified: 2016-01-28

Priority: Not Prioritized

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

View all issues with C++11 status.

Discussion:

As of issue 1171 several time-utility functions have been marked `constexpr`. Alas this was done without adapting the corresponding return elements, which has the effect that none of current arithmetic functions of class template `duration` marked as `constexpr` can ever be `constexpr` functions (which makes them ill-formed, no diagnostics required as of recent core rules), because they invoke a non-constant expression, e.g. 29.5.6 [time.duration.nonmember]/2:

>     template <class Rep1, class Period1, class Rep2, class Period2>
>     constexpr typename common_type<duration<Rep1, Period1>, duration<Rep2, Period2>{>}::type
>     operator+(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);

>     2 Returns: CD(lhs) += rhs.

The real problem is, that we cannot defer to as-if rules here: The returns element specifies an indirect calling contract of a potentially user-defined function. This cannot be the `+=` assignment operator of such a user-defined type, but must be the corresponding immutable binary `operator+` (unless we require that `+=` shall be an immutable function which does not really makes sense).

[2011-02-17 Reflector discussion]

Moved to Tentatively Ready after 5 votes.

Proposed resolution:

The suggested wording changes are against the working draft N3242. Additional to the normative wording changes some editorial fixes are suggested.

1. In 29.5.6 [time.duration.nonmember], change the following arithmetic function specifications as follows:

   >     template <class Rep1, class Period1, class Rep2, class Period2>
   >     constexpr typename common_type<duration<Rep1, Period1>, duration<Rep2, Period2>{>}::type
   >     operator+(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);

   > > 2 Returns: `CD(lhs) += rhs` `CD(CD(lhs).count() + CD(rhs).count())`.

   >     template <class Rep1, class Period1, class Rep2, class Period2>
   >     constexpr typename common_type<duration<Rep1, Period1>, duration<Rep2, Period2>{>}::type
   >     operator-(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);

   > > 3 Returns: `CD(lhs) -= rhs` `CD(CD(lhs).count() - CD(rhs).count())`.

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

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

   > > 5 Returns: `duration<CR(Rep1, Rep2), Period>(d) *= s` `CD(CD(d).count() * s)`.

   > `[...]`

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

   > > 8 Remarks: This operator shall not participate in overload resolution unless `Rep2` is implicitly convertible to `CR(Rep1, Rep2)` and `Rep2` is not an instantiation of `duration`.

   > > 9 Returns: `duration<CR(Rep1, Rep2), Period>(d) /= s` `CD(CD(d).count() / s)`.

   > `[...]`

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

   > > 11 Remarks: This operator shall not participate in overload resolution unless `Rep2` is implicitly convertible to `CR(Rep1, Rep2)` and `Rep2` is not an instantiation of `duration`.

   > > 12 Returns: `duration<CR(Rep1, Rep2), Period>(d) %= s` `CD(CD(d).count() % s)`

   >     template <class Rep1, class Period1, class Rep2, class Period2>
   >     constexpr typename common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type
   >     operator%(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);

   > > 13 Returns: `common_type<duration<Rep1, Period1>, duration<Rep2, Period2> >::type(lhs) %= rhs` `CD(CD(lhs).count() % CD(rhs).count())`.