Контрольная политика контролирует, как класс<interval>будет иметь дело с особыми случаями, такими как: пустые интервалы, бесконечные числа, недействительные значения.
Например, давайте рассмотрим<operator+(interval, T)>. Второй аргумент может быть недействительным значением (для числа с плавающей точкой это NaN). Что делать в таком случае? Во-первых, можно сказать, что второй аргумент никогда не может быть недействительным числом. Во-вторых, можно сказать, что такая ситуация может возникнуть, но она запрещена. В-третьих, мы могли бы разрешить такие значения и генерировать пустой интервал при встрече. И есть много других возможностей.
Именно по этой причине используется такая политика: есть много интересных поведений и было бы грустно произвольно выбирать одно из них.
Requirements
Контрольный класс должен удовлетворять следующему требованию (в виде интерфейса):
/* requirements for checking policy */
struct checking
{
static T pos_inf();
static T neg_inf();
static T nan();
static bool is_nan(const T&);
static T empty_lower();
static T empty_upper();
static bool is_empty(const T&, const T&);
};
Первые две функции,<pos_inf>и<neg_inf>, вызываются каждый раз, когда библиотека должна создать бесконечную границу интервала. Например,<interval::whole>вычисляет<interval(checking::neg_inf(), checking::pos_inf())>. Если допускаются бесконечные значения и<std::numeric_limits<T>::infinity()>возвращается правильное значение, такое значение может быть использовано.
Следующий<nan>. Эта функция используется каждый раз, когда функция должна возвращать значение типа<T>, но не может вычислить его. Это происходит только тогда, когда один из аргументов функции недействителен. Например, если вы спросите, какое среднее значение пустого интервала,<nan>будет использоваться. Но, пожалуйста, помните:<lower>и<upper>непосредственно возвращают значение, запасенное в интервале; поэтому, если интервал пуст,<lower>не ответит<by>на призыв к<checking::nan>(но вернет то же значение, что<checking::empty_lower>мог бы вернуть).
<empty_lower>и<empty_upper>соответственно возвращают нижнюю и верхнюю границы пустого интервала. Нет требований для<empty_lower>и<empty_upper>возвратить такое же значение, как<checking::nan>. Например, если тип<T>не имеет недействительного значения, функции<empty_>могут возвращать интервал [1;0].
<is_nan>используется для проверки того, является ли значение типа<T>недействительным или нет.<is_empty>проверяет, является ли интервал, образованный двумя аргументами, пустым или нет. Такие тесты обычно проводятся в начале каждой функции, которая включает в себя аргумент типа<T>. Если один из входов объявлен недействительным, функция попытается произвести недействительное значение или входной интервал.
Для упрощения настройки политики в библиотеке уже определены некоторые шаблоны.
Прежде всего, это<checking_base>. Благодаря информации, предоставленной<std::numeric_limits<T>>, этот класс способен генерировать базу для политики. Если<T>имеет тихие NaNs (как сказано<numeric_limits::has_quiet_NaN>), то значение используется для<nan>,<empty_lower>,<empty_upper>; и основной тест используется для<is_nan>(это<x!=x>). Если<T>не имеет тихих NaNs, то<nan>является<assert(false)>, пустой интервал [1,0], и<is_nan>всегда возвращается<false>.<nan>,<pos_inf>возвращает<numeric_limits::infinity()>, если это возможно, или<assert(false>.<neg_inf>Возвращается обратно. Наконец,<is_empty(T l,T u)>всегда определяется<!(l<=u)>.
Следующий<checking_no_empty>. Используя это означает, что каждый раз, когда должен быть произведен пустой интервал (по<empty_lower>и<empty_upper>), объект функции, данный аргументом<Exception>шаблона, вызывается и значение, которое он возвращает, распространяется. Таким образом, если<Exception>правильно определено (например, он может бросить исключение, отсюда и название аргумента), вы можете быть уверены, что пустой интервал никогда не будет создан. Так<is_empty>всегда вернется<false>(поскольку нет необходимости тестировать пустой интервал). Как уже было сказано ранее, в этом случае мы также можем заменить<nan>на<assert(false)>; вы будете уверены, что никакого недействительного числа никогда не будет произведено. Если этот шаблон не используется, это означает, что все функции могут создавать пустые интервалы, и они правильно имеют дело с пустыми интервальными аргументами.
В конце концов, есть<checking_no_nan>и<checking_catch_nan>. Первый выражает, что функции библиотеки никогда не получат недействительный номер в качестве аргумента. (59) Возвращение<false>. Другой означает, что аргументы могут быть недействительным числом, но в этом случае<is_nan>вызовет объект функции<Exception>и вернется<false>. Действительно, этот шаблон означает, что недействительные числа никогда не должны пробиваться к телу функции. Если ни один из этих двух шаблонов не используется, это неявно означает, что все функции могут получить недействительные аргументы чисел, и они правильно с ними справятся.
Чтобы определить подходящую политику, нужно правильно сказать, чего вы ожидаете от своего интервального класса. Прежде всего, вы заинтересованы в получении пустых интервалов в конце исчисления? Если вы не хотите получать пустые интервалы,<empty_lower>и<empty_upper>должны потерпеть неудачу при вызове (они могут бросить исключение, установить флаг и т. д.). Однако, если никакая функция не в состоянии произвести пустой интервал, больше нет необходимости делать тест, поэтому<is_empty>всегда может вернуться<false>. В этом случае хороший компилятор сделает много оптимизаций.
Вы также можете быть заинтересованы в получении пустых интервалов в конце исчисления. Например, если вам нужно преобразовать массив неопределенных значений (или интервалов) в новый массив интервалов, вы, возможно, не захотите останавливать преобразование при первой встреченной проблеме. Таким образом,<empty_lower>и<empty_upper>должны возвращать подходящие значения для определения пустого интервала (вы можете использовать верхнюю границу, которая не больше или не равна нижней границе, например); и<is_empty>должны быть в состоянии отличить пустые интервалы от действительных интервалов.
Другой важный вопрос: возможно ли, что некоторые базовые числа (объекты типа<T>) недействительны? А если возможно, то допускаются они или нет? Если это невозможно, то не требуется никакого испытания;<is_nan>всегда может вернуться<false>. В этом случае хороший компилятор сделает много оптимизаций. Если аргументы функции могут содержать недействительные числа, два случая должны рассматриваться в зависимости от того, разрешены они или нет. Если они разрешены,<is_nan>просто нужно проверить, являются ли они недействительными или нет. Если они запрещены,<is_nan>должны потерпеть неудачу (исключение, утверждение и т. д.), когда ссылаются на недействительный аргумент и возвращают<false>иначе. Значение, возвращенное<nan>, не имеет никакого интереса, поскольку функции интервала гарантированно не создают недействительные интервальные границы, если пользователь не передает недействительные числа конструкторам. Так что вы можете поставить утверждение внутри, если вы не доверяете библиотеке.
И, наконец, вы должны решить, что делать с<nan>, если это еще не было решено в начале, и с<pos_inf>и<neg_inf>. Эти функции должны возвращать значение или начинать исключительное поведение (особенно если базовый тип не имеет соответствующих значений).
Some examples
Если вам нужна политика проверки, которая позволяет библиотеке правильно манипулировать данными, даже если они содержат недействительные числа и пустые интервалы, тоchecking_base<T>является возможностью.
Если вы не хотите создавать пустые интервалы и не уверены, что все числа действительны, тогдаchecking_catch_nan<T,
checking_no_empty<T> >может помочь вам.
Если все числа действительны и если не предполагается создание пустого интервала (или если вы не хотите, чтобы они были созданы), то вы можете использоватьchecking_no_nan<T, checking_no_empty<T> >. Обратите внимание, что еслиTне имеет способа представления недействительных чисел, то эта политика будет вести себя так же, какchecking_no_empty<T>. Это так называемая «политика дефолта»interval_lib::checking_strict.
Если все числовые данные действительны, но алгоритм может производить и манипулировать пустыми интервалами, то следует использоватьchecking_no_nan<T>.
Аналогичным образом, если недействительные данные должны быть переданы, и алгоритм может манипулировать пустыми интервалами,checking_catch_nan<T>является решением.
Если вы не возражаете против неопределенных результатов, когда создается пустой интервал или интервальное число, лучше всего создать свою собственную политику, перегрузивchecking_baseи изменивis_nanиis_empty, чтобы они всегда возвращалисьfalse. Это, вероятно, самая быстрая политика проверки, однако она страдает от недостаточной безопасности.
Статья Checking policies раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.