В чем причина того, что в std::chrono::duration нет немедленной манипуляции с количеством тиков?
Предположим, у нас есть
#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;
И наш main
похоже
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;
}
В чем причина запрета пользователю манипулировать duration
напрямую?
4 ответа
Это сделано для того, чтобы заставить вас придерживаться строго типизированных значений, а не произвольных значений.
Бьярн Страуструп имеет примеры такого поведения в "Языке программирования C++" (4-е изд., 35.2.1, с. 1011):
" Период представляет собой единичную систему, поэтому нет
=
или же+=
принимая простую ценность. Разрешение это будет похоже на разрешение добавления5
неизвестной единицы СИ на длину в метрах. Рассматривать:
duration<long long, milli> d1{7}; // 7 milliseconds
d1 += 5; // error
[...]
Что бы здесь значило 5? 5 секунд? 5 миллисекунд? [...] Если вы знаете, что вы имеете в виду, проясните это. Например:
d1 += duration<long long, milli>{5}; //OK: milliseconds"
Обоснование состоит в том, чтобы поддерживать целостность единицы времени, которая duration
представляет собой.
Вы можете думать о rep
как не имеющий единицы. Но duration
это имеет единицу времени. Можно добавлять и вычитать секунды в / из секунд. Но нельзя прибавлять секунды и количество без единицы, не делая выражение двусмысленным и нарушая алгебру единиц.
При этом можно умножить и разделить единицу времени на скалярную (без учета единицы) величину, а в результате все равно остается единица времени. Эта библиотека представляет только единицы времени для первой степени или нулевой степени. Единица времени, возведенная в нулевую степень, является скаляром и представлена rep
, Единицы времени также могут иметь силу 2 или более и отрицательные силы. Однако эта библиотека не представляет такие блоки.
При добавлении двух величин единицы должны быть одинаковыми.
При умножении или делении двух величин формируется новая единица измерения (например, км / ч). Когда количества одинаковых единиц умножаются, их показатели добавляются (например, sec * sec == sec^2). Когда количества одинаковых единиц делятся, их показатели вычитаются (например, сек / сек == сек ^0 == скаляр).
std::chrono::duration
библиотека - это согласованное подмножество библиотеки физических величин, которая обрабатывает только единицы времени и только те единицы времени с показателями, равными 0 и 1.
days += d; // Error!
Это потому, что переменная days
в единицах 86 400 секунд и переменной d
без единого целого. Результат добавления количества единиц в скаляр без единиц измерения при стандартном размерном анализе не определяется.
days *= d; // Why is this okay?
days %= d; // And this too?
Потому что умножение и деление величин на единичные скаляры не бессмысленно. Умножение 2 секунд на 2 приводит к 4 секундам.
Попробуйте умножить 2 секунды на 3 секунды; Результатом является количество 6 с единицей "секунд в квадрате". Конечно chrono::duration
не является полной библиотекой юнитов, поэтому у вас не может быть таких юнитов, как квадрат времени, но библиотеки вроде boost.units будут поддерживать это.
Я бы предположил, что это сделано, чтобы заставить вас задуматься над тем, каковы единицы измерения длительности, которые вы хотите сложить / вычесть. Это также не дает вам никаких предположений о том, в каких единицах измерения находятся такты.