Понятие Logical представляет типы с истинным значением.
Интуитивно Logical — это просто bool или что-то, что может действовать как один. Однако в контексте программирования с разнородными объектами становится чрезвычайно важным различать те объекты, истинное значение которых известно во время компиляции, и те, истинное значение которых известно только во время выполнения. Причина, по которой это так важно, заключается в том, что можно разветвляться во время компиляции на условии, истинное значение которого известно во время компиляции, и, следовательно, тип возврата заключающей функции может зависеть от этого истинного значения. Однако, если значение истинности известно только во время выполнения, компилятор должен компилировать обе ветви (потому что любая или обе из них могут в конечном итоге использоваться), что создает дополнительное требование, что обе ветви должны оцениваться к одному и тому же типу.
Более конкретно, Logical (почти) представляет собой булевую алгебру , которая представляет собой математическую структуру, кодирующую обычные свойства, которые позволяют нам рассуждать с bool. Точные свойства, которые должны быть удовлетворены любой моделью Logical, строго указаны в законах ниже.
Truth, falsity and logical equivalence
Logicalx называется true-valued, а иногда и просто true как злоупотребление обозначением, если
Это обеспечивает стандартный способ преобразования любого Logical в прямой bool. Понятие истинной ценности предполагает другое определение, а именно логическую эквивалентность. Мы скажем, что два Logicals x и y являются логически эквивалентными, если они имеют одинаковое значение истины. Чтобы обозначить, что некоторые выражения p и q логического типа данных логически эквивалентны, мы иногда также пишем:
p if and only if q
это очень распространено в математике. Интуиция, стоящая за этой записью, заключается в том, что всякий раз, когда p является истинным значением, тогда q должен быть; но когда p является ложным значением, тогда q также должен быть. Следовательно, p должно быть истинно оценено, когда (и только когда) q истинно оценено.
Minimal complete definition
eval_if, not_ и while_
Все остальные функции можно определить в таких терминах:
Как описано выше, концепция Logical представляет собой булеву алгебру. Обоснование этой слабости состоит в том, чтобы позволить таким вещам, как целые числа, действовать как Логические , которые выровнены с C++, даже если они не образуют булеву алгебру. Несмотря на то, что мы отходим от обычной аксиоматизации булевых алгебр, мы на собственном опыте обнаружили, что данное здесь определение логики в значительной степени совместимо с интуицией.
Следующие законы должны быть выполнены для любого типа данных L, моделирующего концепцию Logical. Пусть a, b и c будут объектами типа данных Logical, и пусть t и f будут произвольными true-valued и false-valuedLogicals этого типа данных соответственно. Тогда,
Тип данных T является арифметическим, если std::is_arithmetic::value является истинным. Для арифметического типа данных T модель Logical обеспечивается автоматически путем использования результата встроенного неявного преобразования в bool в качестве значения истинности. В частности, минимальное полное определение для этих типов данных
while_(pred, state, f) = equivalent to a normal while loop
Rationale for not providing a model for all contextually convertible to bool data types
Метод not_ не может быть реализован для всех этих типов. Например, нельзя отбрасывать тип указателя T*, а затем снова возвращаться к T*. С арифметическим типом T, однако, можно отлить от T до кипения, а затем снова до T; результат будет 0 или 1 в зависимости от значения истинности. Если вы хотите использовать тип указателя или что-то подобное в условном режиме, рекомендуется явно преобразовать его в bool с помощью to.
Return whether all the arguments are true-valued.and_ can be called with one argument or more. When called with two arguments, and_ uses tag-dispatching to find the right implementation. Otherwise,. More...
Conditionally execute one of two branches based on a condition.Given a condition and two branches in the form of lambdas or hana::lazys, eval_if will evaluate the branch selected by the condition with eval and return the result. The exact requirements for what the branches may be are the same requirements as those for the eval function. More...
Conditionally return one of two values based on a condition.Specifically, then is returned iff cond is true-valued, and else_ is returned otherwise. Note that some Logical models may allow then and else_ to have different types, while others may require both values to have the same type. More...
Negates a Logical.This method returns a Logical with the same tag, but whose truth-value is negated. Specifically, not_(x) returns a false-valued Logical if x is a true-valued Logical, and a true-valued one otherwise. More...
Return whether any of the arguments is true-valued.or_ can be called with one argument or more. When called with two arguments, or_ uses tag-dispatching to find the right implementation. Otherwise,. More...
Apply a function to an initial state while some predicate is satisfied.This method is a natural extension of the while language construct to manipulate a state whose type may change from one iteration to another. However, note that having a state whose type changes from one iteration to the other is only possible as long as the predicate returns a Logical whose truth value is known at compile-time. More...
Возвращаем, являются ли все аргументы истинными. и_ можно назвать одним аргументом или более. При вызове с двумя аргументами и_ для поиска правильной реализации используется диспетчеризация тегов. Иначе.
Sequentially compose two monadic actions, discarding any value produced by the first but not its effe...
Definition: then.hpp:36
Условно выполнить одну из двух ветвей на основании условия. При условии и двух ветвях в виде лямбда или hana::lazys, eval_if будет оценивать ветвь, выбранную условием с eval и возвращать результат. Точные требования к ветвям те же, что и для функции eval.
Deferring compile-time evaluation inside eval_if
Пройдя унарный вызов eval_if, можно отложить оценку выбранных выражений внутри лямбды. Это полезно, когда инстанцирование ветви вызовет ошибку времени компиляции; мы хотим, чтобы ветвь была инстанциирована только тогда, когда эта ветвь выбрана. Вот как этого можно достичь.
Для простоты мы будем использовать унарную лямбду в качестве нашего унарного вызова. Наша лямбда должна принимать параметр (обычно называемый _), который может использоваться для отсрочки оценки выражений по мере необходимости. Например,
[=](auto_) { return n * fact(_(n) - hana::int_c<1>); }
);
}
Здесь происходит то, что eval_if вызовет eval в выбранной ветви. В свою очередь, eval будет называть выбранную ветвь либо ничем; для тогда ветвь – или с hana::id – для else ветвь. Поэтому, _(x) всегда совпадает с x, но компилятор не может сказать, пока лямбда не будет вызвана! Следовательно, компилятор должен ждать, прежде чем он инстанцирует тело лямбды, и не происходит бесконечной рекурсии. Однако этот трюк для задержки инстанциации тела лямбды может быть использован только тогда, когда состояние известно во время компиляции, потому что в противном случае обе ветви должны быть инстанцированы внутри eval_if.
Есть несколько предостережений, которые следует отметить при таком подходе к ленивому ветвлению. Во-первых, поскольку мы используем лямбда, это означает, что результат функции не может быть использован в постоянном выражении. Это ограничение нынешнего языка.
Вторая оговорка заключается в том, что у компиляторов в настоящее время есть несколько ошибок в отношении глубоко вложенных лямбд с захватами. Таким образом, вы всегда рискуете разбить компилятор, но это вопрос времени, прежде чем это больше не проблема.
Наконец, это означает, что условия не могут быть написаны непосредственно в неоцененных контекстах. Причина в том, что лямбда не может появиться в неоцененном контексте, например, в деклатипе . Один из способов обойти это — полностью перевести вычисления вашего типа в переменные шаблоны. Вместо того, чтобы писать
using pointerize = decltype(pointerize_impl(hana::type_c<T>));
Примечание : Этот пример на самом деле будет реализован легче с частичными специализациями, но мой пакет хороших примеров пуст на момент написания этого.
Теперь этот прыжок с обруча должен быть сделан только в одном месте, потому что вы должны использовать нормальную нотацию функций везде в вашей метапрограмме для выполнения вычислений типов. Таким образом, синтаксическая стоимость амортизируется по всей программе.
Другим способом обойти это ограничение языка было бы использование hana::lazy для ветвей. Однако это подходит только тогда, когда ветви не слишком сложны. С hana::lazy вы можете написать предыдущий пример как
Sequentially compose two monadic actions, discarding any value produced by the first but not its effe...
Definition: then.hpp:36
Условно возвращайте одно из двух значений на основании условия. В частности, , затем возвращается iff cond является истинным значением, а else_ возвращается в противном случае. Обратите внимание, что некоторые Логические Модели могут позволять , затем и else_ иметь разные типы, в то время как другие могут требовать, чтобы оба значения имели один и тот же тип.
Parameters
cond
Условие, определяющее, какое из двух значений возвращается.
then
Значение, возвращаемое при cond, является истинным.
else_
Значение, возвращаемое при cond, является ложным.
Example
// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
Отрицает логическое . Этот метод возвращает Logical с тем же тегом, но истинное значение которого отрицается. В частности, not_(x) возвращает неверно оцененный Logical, если x является истинно оцененным Logical, и истинно оцененным в противном случае.
Example
// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
Возвращаем, является ли любой из аргументов истинным. или_ можно назвать одним аргументом или более. При вызове с двумя аргументами or_ использует метку-диспетчеризацию, чтобы найти правильную реализацию. Иначе.
Примените функцию к начальному состоянию, пока некоторый предикат удовлетворен. Этот метод является естественным расширением структуры языка , в то время как для манипулирования состоянием, тип которого может изменяться от одной итерации к другой. Однако обратите внимание, что наличие состояния, тип которого изменяется от одной итерации к другой, возможно только до тех пор, пока предикат возвращает логическое , истинное значение которого известно во время компиляции.
В частности, while_(pred, state, f) эквивалентно
f(...f(f(state)))
где f повторяется до тех пор, пока pred(f(...)) является истинным значением Logical.
Parameters
pred
Предикат, вызванный состоянием или результатом применения f определенное количество раз в состояние, и возвращать, следует ли применять f еще один раз.
state
Начальное состояние, при котором применяется f.
f
Функция, которая повторяется в начальном состоянии. Обратите внимание, что тип возврата f может изменяться от одной итерации к другой, но только тогда, когда pred возвращает время компиляции Logical. Другими словами, decltype(f(stateN)) может отличаться от decltype(f(stateN+1)), но только если pred(f(stateN)) возвращает время компиляции Logical.
Example
// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
Статья Boost.Hana: Logical раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.