duration
non-member arithmetic requirementsSection: 30.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 thecommon_type
ofRep1
andRep2
. BothRep1
andRep2
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 thecommon_type
ofRep1
andRep2
. BothRep1
andRep2
shall be implicitly convertible toCR
, 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 thecommon_type
ofRep1
andRep2
. BothRep1
andRep2
shall be implicitly convertible toCR
, andRep2
shall not be an instantiation ofduration
, 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
andRep2
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 30.5.8 [time.duration.cast].
Proposed resolution:
Change the requirements clauses under 30.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 toCR(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 toCR(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 existRep2
shall be implicitly convertible toCR(Rep1, Rep2)
andRep2
shall not be an instantiation ofduration
. Diagnostic required.