time_point
non-member subtraction with an unsigned durationSection: 30.6.6 [time.point.nonmember] Status: C++17 Submitter: Michael Winterberg Opened: 2016-06-23 Last modified: 2017-07-30
Priority: 0
View all other issues in [time.point.nonmember].
View all issues with C++17 status.
Discussion:
In N4594, 30.6.6 [time.point.nonmember], operator-(time_point, duration)
is specified as:
template <class Clock, class Duration1, class Rep2, class Period2> constexpr time_point<Clock, common_type_t<Duration1, duration<Rep2, Period2>>> operator-(const time_point<Clock, Duration1>& lhs, const duration<Rep2, Period2>& rhs);-3- Returns:
lhs + (-rhs)
.
When Rep2
is an unsigned integral type, the behavior is quite different with arithmetic of the underlying
integral types because of the requirement to negate the incoming duration and then add that. It also ends up
producing different results than the underlying durations as well as the non-member time_point::operator-=
.
#include <chrono> #include <iostream> #include <cstdint> using namespace std; using namespace std::chrono; int main() { const duration<uint32_t> unsignedSeconds{5}; auto someValue = system_clock::from_time_t(200); cout << system_clock::to_time_t(someValue) << '\n'; cout << system_clock::to_time_t(someValue - unsignedSeconds) << '\n'; someValue -= unsignedSeconds; cout << system_clock::to_time_t(someValue) << '\n'; std::chrono::seconds signedDur{200}; cout << signedDur.count() << '\n'; cout << (signedDur - unsignedSeconds).count() << '\n'; signedDur -= unsignedSeconds; cout << signedDur.count() << '\n'; }
The goal of the program is to compare the behavior of time_point
non-member operator-
,
time_point
member operator-=
, duration
non-member operator-
, and
duration
member operator-=
with basically the same inputs.
200 4294967491 195 200 195 195
On the other hand, libstdc++ produces this output, which is what I "intuitively" expect and behaves more consistently:
200 195 195 200 195 195
Given the seemingly brief coverage of durations with unsigned representations in the standard, this seems to be an oversight rather than a deliberate choice for this behavior. Additionally, there may be other "unexpected" behaviors with durations with an unsigned representation, this is just the one that I've come across.
[2016-07 Chicago]
Monday: P0 - tentatively ready
Proposed resolution:
This wording is relative to N4594.
Change 30.6.6 [time.point.nonmember] as indicated:
template <class Clock, class Duration1, class Rep2, class Period2> constexpr time_point<Clock, common_type_t<Duration1, duration<Rep2, Period2>>> operator-(const time_point<Clock, Duration1>& lhs, const duration<Rep2, Period2>& rhs);-3- Returns:
lhs + (-rhs)
CT(lhs.time_since_epoch() - rhs)
, whereCT
is the type of the return value.