Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the reason behind std::chrono::duration's lack of immediate tick count manipulation?

Tags:

c++

c++11

chrono

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?

like image 708
rwols Avatar asked Jul 18 '13 20:07

rwols


People also ask

How does STD Chrono work?

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 .

Which Chrono function allows us to convert a clock duration from one unit to the other?

std::chrono::duration_cast.

What is duration in C++?

(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.


3 Answers

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 of 5 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"

like image 188
Pixelchemist Avatar answered Nov 01 '22 17:11

Pixelchemist


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.

like image 22
Howard Hinnant Avatar answered Nov 01 '22 15:11

Howard Hinnant


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.

like image 8
bames53 Avatar answered Nov 01 '22 15:11

bames53