Ниже я игнорирую пространства имен для краткости. duration
находится в пространстве имен std::chrono
, а ratio
— в пространстве имен std
.
Есть два хороших способа всегда гарантировать, что ваш ratio
будет уменьшен до самых низких значений без необходимости выполнять арифметические действия самостоятельно. Первый довольно прямой:
Прямая формулировка
Если вы просто хотите сразу перейти к microfortnights
, но не выясняя, что сокращенная дробь 86 400*14/1 000 000 равна 756/625, просто добавьте ::type
после ratio
:
using microfortnights = duration<long, ratio<86400*14, 1000000>::type>;
Вложенное type
каждого ratio<N, D>
— это еще одно ratio<Nr, Dr>
, где Nr/Dr
— сокращенная дробь N/D
. Если N/D
уже уменьшено, то ratio<N, D>::type
имеет тот же тип, что и ratio<N, D>
. В самом деле, если бы я уже понял, что 756/625 — правильная сокращенная дробь, но был бы просто параноиком, думая, что ее можно еще уменьшить, я мог бы написать:
using microfortnights = duration<long, ratio<756, 625>::type>;
Поэтому, если у вас есть какие-либо сомнения в том, что ваш ratio
выражен в самых низких терминах, или вы просто не хотите возиться с проверкой, вы всегда можете добавить ::type
к вашему типу ratio
, чтобы быть уверенным.
Подробная формулировка
Пользовательские единицы продолжительности времени часто появляются как часть семейства. И часто удобно иметь всю семью доступной для вашего кода. Например, microfortnights
очевидно связано с fortnights
, которое, в свою очередь, связано с weeks
, производным от days
, производным от hours
(или от seconds
, если хотите).
Создавая свою семью по одному элементу за раз, вы не только делаете доступной всю семью, но и снижаете вероятность ошибок, связывая одного члена семьи с другим с помощью простейшего преобразования. Кроме того, использование std::ratio_multiply
и std::ratio_divide
вместо умножения литералов также означает, что вам не нужно постоянно вставлять ::type
, чтобы гарантировать, что вы сохраняете ratio
в наименьших выражениях.
Например:
using days = duration<long, ratio_multiply<hours::period, ratio<24>>>;
ratio_multiply
– это имя-определения-типа, полученное в результате умножения, уже приведенного к наименьшим терминам. Таким образом, вышеприведенное является точно тем же типом, что и:
using days = duration<long, ratio<86400>>;
Вы даже можете иметь оба определения в одной и той же единице перевода, и вы не получите ошибку переопределения. В любом случае теперь вы можете сказать:
using weeks = duration<long, ratio_multiply<days::period, ratio<7>>>;
using fortnights = duration<long, ratio_multiply<weeks::period, ratio<2>>>;
using microfortnights = duration<long, ratio_multiply<fortnights::period, micro>>;
И мы получили имя_типа для microfortnights
, которое является точно тем же типом, что и в нашей прямой формулировке, но с помощью ряда гораздо более простых преобразований. Нам по-прежнему не нужно возиться с сокращением дробей до наименьших членов, и теперь у нас есть несколько полезных единиц измерения вместо одной.
Также обратите внимание на использование std::micro
вместо std::ratio<1, 1000000>
. Это еще одно место, где можно избежать ошибок по невнимательности. Так легко (по крайней мере, для меня) напечатать (и неправильно прочитать) количество нулей.
person
Howard Hinnant
schedule
10.01.2015
std::ratio
? Кажется, что общая тема имеет очень мало общего сchrono
, за исключением выбранного примера? - person sehe   schedule 10.01.2015durations
, иначе я боюсь, что моя аудитория не увидит практического примененияratio
. Я добавилratio
к заголовку, чтобы при поискеratio
было легче найти этот вопрос/ответ. - person Howard Hinnant   schedule 11.01.20152000000
микродней неfour_weeks
, а неtwo_weeks
? - person Nemo   schedule 25.03.2015