Ответ 1
Ниже я игнорирую пространства имен в интересах краткости. 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
является typedef-именем для результата умножения, уже приведенного к младшим. Таким образом, вышесказанное является тем же самым типом, что и:
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>>;
И мы закончили с typedef-name для microfortnights
, который является тем же самым типом, что и в нашей прямой формулировке, но через серию гораздо более простых преобразований. Нам все еще не нужно беспокоиться об уменьшении фракций до самых низких значений, и теперь у нас есть несколько полезных единиц, а не только один.
Также обратите внимание на использование std::micro
вместо std::ratio<1, 1000000>
. Это еще одно место, чтобы избежать неосторожных ошибок. Это так просто (по крайней мере для меня), чтобы ввести в заблуждение (и неправильно прочитать) количество нулей.