Suppose we have
#include <chrono>
#include <iostream>
#include <ctime>
namespace Ratios { typedef std::ratio<60*60*24,1> Days; }
typedef std::chrono::system_clock Clock;
typedef Clock::time_point TimePoint;
And our main
looks like
int main(int argc, char *argv[])
{
// argc check left out for brevity
const Clock::rep d = static_cast<Clock::rep>(std::atoi(argv[1]));
// Right now
TimePoint now = Clock::now();
// Start with zero days
auto days = std::chrono::duration<Clock::rep, Ratios::Days>::zero();
// Now we'd like to add d to the days
days += d; // Error!
days.count() = d; // Error!
days = days + d; // Error!
days += std::chrono::duration<Clock::rep, Ratios::Days>(d); // Okay
days = days + std::chrono::duration<Clock::rep, Ratios::Days>(d); // Okay
days *= d; // Why is this okay?
days %= d; // And this too?
TimePoint later = now + days;
return 0;
}
What is the reason behind prohibiting the user to manipulate a duration
directly?
Class template std::chrono::duration represents a time interval. It consists of a count of ticks of type Rep and a tick period, where the tick period is a compile-time rational fraction representing the time in seconds from one tick to the next. The only data stored in a duration is a tick count of type Rep .
std::chrono::duration_cast.
(C++11 feature) Class template std::duration represents a time interval. It is represented by a count of ticks and a tick period, where the tick period is the number of seconds from one tick to the next, represented as a compile-time rational constant.
It is done to enforce you to stick to strongly typed values rather than arbitrary values.
Bjarne Stroustrup has examples regarding this behaviour in "The C++ Programming Language" (4th Ed., 35.2.1, pp. 1011):
"The period is a unit system, so there is no
=
or+=
taking a plain value. Allowing that would be like allowing the addition of5
of an unknown SI unit to a length in meters. Consider:
duration<long long, milli> d1{7}; // 7 milliseconds
d1 += 5; // error
[...]
What would 5 mean here? 5 seconds? 5 milliseconds? [...] If you know what you mean, be explicit about it. For example:
d1 += duration<long long, milli>{5}; //OK: milliseconds"
The rationale is to maintain the integrity of the unit of time which duration
represents.
You can think of the rep
as being unit-less. But the duration
is has a unit of time. One can add and subtract seconds to/from seconds. But one can not add seconds and a unit-less quantity without making the expression ambiguous, and violating the algebra of units.
That being said, one can multiply and divide a unit of time by a scalar (a unit-less) quantity, and the result is still a unit of time. This library only represents units of time to the first power, or zero power. A unit of time raised to the zero power is a scalar and is represented by rep
. Units of time can also have power of 2 or more, and negative powers. However this library does not represent such units.
When adding two quantities, the units must be the same.
When multiplying or dividing two quantities, a new unit is formed (e.g. km/hr). When quantities of the same units are multiplied, their exponents are added (e.g. sec * sec == sec^2). When quantities of the same units are divided, their exponents are subtracted (e.g. sec / sec == sec^0 == a scalar).
The std::chrono::duration
library is a consistent subset of a physical quantities library that handles only units of time and only those units of time with exponents equal to 0 and 1.
days += d; // Error!
This is because the variable days
is in units of 86,400 seconds and the variable d
is unitless. The result of adding a quantity of one unit to a unitless scalar is not defined under standard dimensional analysis.
days *= d; // Why is this okay?
days %= d; // And this too?
Because multiplying and dividing quantities by unitless scalars is not meaningless. Multiplying 2 seconds by 2 results in 4 seconds.
Consider multiplying 2 seconds by 3 seconds; the result is a quantity 6 with the unit 'seconds squared'. Of course chrono::duration
isn't a complete units library so you can't have units like time squared, but libraries like boost.units will support that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With