constexpr
functions have invalid effectsSection: 30.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. 30.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.
In 30.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
5 Returns:Rep2
is implicitly convertible toCR(Rep1, Rep2)
.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
9 Returns:Rep2
is implicitly convertible toCR(Rep1, Rep2)
andRep2
is not an instantiation ofduration
.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
12 Returns:Rep2
is implicitly convertible toCR(Rep1, Rep2)
andRep2
is not an instantiation ofduration
.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())
.