Почему `std :: chrono :: weekday` позволяет, но не сохраняет значения за пределами допустимого диапазона? - PullRequest
0 голосов
/ 04 января 2019

Согласно разделу [time.cal.wd.overview] / 1 стандарта C ++:

weekday представляет день недели в гражданском календаре. Обычно он хранит значения в диапазоне от 0 до 6, соответствующие с воскресенья по субботу, но может содержать неотрицательные значения вне этого диапазона.

В то же время арифметические операции выполняют по модулю 7 арифметического воздействия, получая результат в диапазоне [0, 6], например

weekday wd(7);
// wd.ok() == false - wd is invalid
++wd; // wd == weekday(1)
// wd.ok() == true  - wd silently becomes valid

Почему weekday имеет такое своеобразное поведение, в частности, почему значения вне [0, 6] разрешены, но не сохранены арифметическими операциями?

Ответы [ 3 ]

0 голосов
/ 04 января 2019

Почему день недели имеет такое специфическое поведение, особенно почему значения вне [0, 6] разрешены, но не сохранены арифметическими операциями?

Любая арифметическая операция на weekday потенциально может быть переполнена. Таким образом, у вас есть для выполнения операции по модулю. Важно, что sat + days{1} == sun, так как это то, что все ожидают. И вы действительно хотите, чтобы (sat + days{1}).ok() также сохранял, так как это действительно верно. И так же важно, что sat + days{8} == sun и sat + days{701} == sun, и так далее. Вот как работает календарная арифметика.

Так что довольно необходимо выполнить модуль 7 для всех арифметических операций. Нет никакого смысла держать 8 в качестве значения дня недели - это не совсем правильный день недели.

С другой стороны, выполнение модуля по конструкции не имеет такой большой ясной ценности. Это дополнительная работа, которая вам может не понадобиться, и она может даже скрывать ошибки. Что если вы хотите просто проверить weekday(user_input).ok()? Будет ли каждый, кто должен знать, что проверить внешне?

Короче говоря, значения выше 6 допускаются при построении, потому что это имеет смысл разрешать, но арифметика не сохраняет их, потому что их не имеет смысла сохранять.

Но Ховард часто участвует в SO, поэтому он, вероятно, ответит лучшим ответом .

0 голосов
/ 04 января 2019

Конструктор weekday(unsigned wd) обещает хранить любое значение в диапазоне [0, 255]. Обоснование этого:

  1. Это очень быстро.
  2. Позволяет клиенту присвоить «неиспользуемое» значение чему-то полезному в логике клиента.

Для примера (2):

constexpr weekday not_a_weekday{255};
...
weekday wd = not_a_weekday;
in >> wd;
if (wd == not_a_weekday)
    throw "oops";

weekday арифметика возвращает диапазон обратно в [0, 6], потому что если вы напишите алгоритм для выполнения арифметики по модулю 7, без проверки диапазона вообще, это то, что естественно происходит. То есть это самая быстрая вещь.


Итак, подведем итог: производительность - это обоснование для текущей спецификации weekday в сочетании с sizeof, который настолько мал, насколько это возможно (что также может способствовать повышению производительности).

Тем не менее, учитывая максимально возможную производительность, любое поведение, оставшееся (происходящее естественным образом), может быть полезным для стандартизации и позволяет клиентам использовать преимущества этого поведения, а не говорить, что они являются неопределенным поведением TM .

Действительно, спецификация максимально избегает UB, вместо этого выбрав Unspecified Behavior. Например, weekday{300} может не хранить желаемое значение, но не может переформатировать ваш диск, и оптимизатору не разрешается делать вид, что код не существует.

0 голосов
/ 04 января 2019

Это не так странно.

Если вы дадите ему значение вне допустимого диапазона, то это ваша ошибка. Было бы несправедливо заставлять нас всех терпеть бесконечные проверки, чтобы поймать это редкое явление.

Точно так же нечестно ожидать, что четко определенные операции этого типа будут делать что-то, в частности, со значениями, которые явно считаются вне диапазона, и при этом неясно, какого рода детерминированный результат вы ожидаете от такой операции. , Какой день наступит после "ooglebooglebargleday"?

Вы найдете эту философию во всем C ++. Вы не платите за то, что не используете, и можете выстрелить себе в ногу, если не возражаете против того, чтобы нести себя до конца дома.

...