В чем разница между chrono :: month и chrono :: months

105

В чем разница между типами / значениями хронографов C ++ 20 month{7}и months{7}? Разве не сбивает с толку два таких похожих имени?

Говард Хиннант
источник

Ответы:

129

Да, это может сбивать с толку , чтобы иметь как monthи monthsпри первом возникновении этой библиотеки. Однако в этой библиотеке есть согласованные соглашения об именах, которые помогают уменьшить эту путаницу. И преимущество заключается в четком разделении отдельной семантики при сохранении коротких интуитивно понятных имен.

months

Все "предопределенные" chrono::durationтипы имеют множественное число:

  • nanoseconds
  • microseconds
  • milliseconds
  • seconds
  • minutes
  • hours
  • days
  • weeks
  • months
  • years

Так monthsэто chrono::durationтип :

используя месяцы = продолжительность < целочисленный тип со знаком длиной не менее 20 бит ,
                         ratio_divide <годы :: период, коэффициент <12> >>;

И это именно 1 / +12 о years.

static_assert(12*months{1} == years{1});

Распечатать его можно так:

cout << months{7} << '\n';

И вывод:

7[2629746]s

Это означает 7 единиц по 2629746 единиц. Оказывается, 2 629 746 секунд - это средняя продолжительность месяца по гражданскому календарю. Говорят иначе:

static_assert(months{1} == 2'629'746s);

(точное число не имеет особого значения, кроме ставок на выигрышную планку)

month

month(в единственном числе), с другой стороны, не является chrono::duration. Это календарный указатель месяца в году в гражданском календаре. Или:

static_assert(month{7} == July);

Это можно использовать для создания такой даты:

auto independence_day = month{7}/4d/2020y;

Алгебра monthи monthsотражает эту разную семантику. Например, «июль + июль» не имеет смысла и, следовательно, является ошибкой времени компиляции:

auto x = month{7} + month{7};
         ~~~~~~~~ ^ ~~~~~~~~
error: invalid operands to binary expression ('std::chrono::month' and 'std::chrono::month')

Но в этом есть смысл:

auto constexpr x = month{7} + months{7};
static_assert(x == February);

И это:

auto constexpr x = months{7} + months{7};
static_assert(x == months{14});

И все еще:

auto b = February == months{14};
         ~~~~~~~~ ^  ~~~~~~~~~~
error: invalid operands to binary expression ('const std::chrono::month' and 'std::chrono::months')

Т.е. monthи monthsне только не равны, они даже не сопоставимы. Это яблоки и апельсины, если вам нравятся аналогии с фруктами. ;-)

Аналогичная связь существует между dayи days. А между yearи years.


Если это множественное число, это chrono::duration.


И только <chrono>безопасность типов помогает гарантировать, что эти две семантически разные, но похожие концепции не будут перепутаны друг с другом в вашем коде.

Говард Хиннант
источник
Гарантированно ли это будет верно July == July + months(12*x)независимо от x? Даже если x является INT_MAX?
PiotrNycz
3
Почти. Если происходит 12*xпереполнение, у вас тут же неопределенное поведение (до monthsзапуска конструктора). Однако, если значение monthsкратно 12 (положительному или отрицательному), то да, сложение (или вычитание) по существу не работает. Вы получите то же самое, что и July == July + years(x).
Ховард Хиннант,
Вы задали свой вопрос 17:58 и тоже ответили на него в 17:58?
dejoma
2
Ответить на свой вопрос не только нормально, но и настоятельно рекомендуется: stackoverflow.blog/2011/07/01/… , stackoverflow.com/help/self-answer
Говард Хиннант,