Я только что пришел в проект с довольно большой кодовой базой.
Я в основном имею дело с C ++, и большая часть кода, который они пишут, использует двойное отрицание для своей логической логики.
if (!!variable && (!!api.lookup("some-string"))) {
do_some_stuff();
}
Я знаю, что эти ребята умные программисты, очевидно, что они делают это не случайно.
Я не опытный эксперт по C ++, я только догадываюсь, почему они это делают, так это то, что они хотят сделать абсолютно уверенным, что оцениваемое значение является фактическим логическим представлением. Таким образом, они отрицают это, а затем снова отрицают, чтобы вернуть его фактическое логическое значение.
Это правильно, или я что-то упускаю?
Ответы:
Это уловка для преобразования в логическое значение.
источник
bool
типа, чтобы избежать хранения значений, отличных от логических переменных1
и0
в них.!!
или!=0
решая проблему, и среди двух я нахожу первый очиститель (поскольку он будет работать с большим количеством типов). Также я согласен с тем, что нет причин использовать их в рассматриваемом коде.На самом деле это очень полезная идиома в некоторых контекстах. Возьмите эти макросы (пример из ядра Linux). Для GCC они реализованы следующим образом:
Зачем им это нужно? GCC
__builtin_expect
обрабатывает свои параметры какlong
и нетbool
, поэтому должна быть какая-то форма преобразования. Поскольку они не знают, чтоcond
именно, когда они пишут эти макросы, наиболее общим является использование этой!!
идиомы.Вероятно, они могли бы сделать то же самое, сравнивая с 0, но, на мой взгляд, на самом деле сделать двойное отрицание проще, поскольку это ближе всего к преобразованию в логическое значение, которое есть у C.
Этот код можно использовать и в C ++ ... это вещь с наименьшим общим знаменателем. Если возможно, делайте то, что работает как в C, так и в C ++.
источник
Кодировщики думают, что он преобразует операнд в bool, но поскольку операнды && уже неявно преобразованы в bool, это полностью избыточно.
источник
Это метод, позволяющий избежать записи (переменная! = 0), т. Е. Преобразования любого типа в логическое значение.
Подобному коду IMO нет места в системах, которые необходимо поддерживать - потому что это не сразу читаемый код (отсюда и вопрос в первую очередь).
Код должен быть разборчивым - иначе вы оставите наследство временного долга на будущее, поскольку требуется время, чтобы понять что-то излишне запутанное.
источник
bool(expr)
: оно действует правильно, и все понимают его намерения с первого взгляда.!!(expr)
это двойное отрицание, которое случайно преобразуется в bool ... это непросто.Да, это правильно, и нет, вы чего-то не упускаете.
!!
это преобразование в логическое значение. См. Этот вопрос для дальнейшего обсуждения.источник
Это обходит стороной предупреждение компилятора. Попробуй это:
Строка 'bar' генерирует «принудительное преобразование значения в bool 'true' или 'false' (предупреждение о производительности)» в MSVC ++, но строка 'baz' проходит нормально.
источник
bool
типе - все кодируется как0
или1
вint
.Оператор! перегружен?
В противном случае они, вероятно, делают это, чтобы преобразовать переменную в логическое значение без предупреждения. Это определенно нестандартный способ ведения дел.
источник
Разработчики Наследство C не имели логический тип, поэтому они часто
#define TRUE 1
и#define FALSE 0
затем используются произвольные числовые типы данных для булевых сравнений. Теперь, когда у нас естьbool
, многие компиляторы будут выдавать предупреждения, когда определенные типы назначений и сравнений выполняются с использованием смеси числовых типов и логических типов. Эти два использования в конечном итоге столкнутся при работе с устаревшим кодом.Чтобы обойти эту проблему, некоторые разработчики используют следующий логический идентификатор:
!num_value
возвращаетbool true
ifnum_value == 0
;false
в противном случае.!!num_value
возвращает,bool false
еслиnum_value == 0
;true
в противном случае. Одного отрицания достаточно, чтобы преобразоватьnum_value
вbool
; однако двойное отрицание необходимо для восстановления первоначального смысла булевого выражения.Этот шаблон известен как идиома , т. Е. Что- то, что обычно используется людьми, знакомыми с языком. Поэтому я не вижу в этом антипаттерна, в большей степени, чем хотелось бы
static_cast<bool>(num_value)
. Приведение вполне может дать правильные результаты, но некоторые компиляторы затем выдают предупреждение о производительности, поэтому вам все равно нужно это исправить.Другой способ решения этой проблемы есть
(num_value != FALSE)
. Я тоже согласен с этим, но в целом!!num_value
он гораздо менее подробен, может быть более ясным и не сбивает с толку, когда вы видите это во второй раз.источник
!!
использовался для работы с исходным C ++, у которого не было логического типа (как и C).Пример проблемы:
Внутри
if(condition)
, наcondition
потребности оценить в какой - то тип , какdouble, int, void*
и т.д., но неbool
так как она еще не существует.Скажем, существует класс
int256
(256-битное целое число) и все целочисленные преобразования / преобразования были перегружены.Чтобы проверить, было ли оно
x
«истинным» или ненулевым, нужноif (x)
преобразоватьx
в некоторое целое число, а затем оценить,int
было ли оно ненулевым. Типичная перегрузка(int) x
возвращает только LS битыx
.if (x)
тогда только тестировал LS битыx
.Но у C ++ есть
!
оператор. Перегрузка!x
обычно оценивает все битыx
. Итак, чтобы вернуться к неинвертированной логикеif (!!x)
.Ref Использовали ли старые версии C ++ оператор класса int при вычислении условия в операторе if ()?
источник
Как упоминал Марчин , это может иметь значение, если перегрузка оператора происходит. В противном случае в C / C ++ это не имеет значения, кроме случаев, когда вы выполняете одно из следующих действий:
прямое сравнение
true
(или в C что-то вродеTRUE
макроса), что почти всегда плохая идея. Например:if (api.lookup("some-string") == true) {...}
вам просто нужно что-то преобразовать в строгое значение 0/1. В C ++ присвоение a
bool
будет делать это неявно (для тех вещей, которые неявно конвертируются вbool
). В C или если вы имеете дело с переменной, отличной от bool, я видел эту идиому, но я предпочитаю ее(some_variable != 0)
разнообразие.Я думаю, что в контексте более крупного логического выражения это просто загромождает вещи.
источник
Если переменная имеет объектный тип, она может иметь! оператор определен, но не приведен к типу bool (или, что еще хуже, неявно приведен к типу int с другой семантикой. Двойной вызов оператора! приводит к преобразованию в тип bool, которое работает даже в странных случаях.
источник
Это правильно, но в C здесь бессмысленно - 'if' и '&&' будут обрабатывать выражение таким же образом без '!!'.
Я полагаю, что причина сделать это в C ++ в том, что '&&' может быть перегружен. Но тогда тоже может '!', Поэтому на самом деле это не гарантирует, что вы получите bool, не глядя на код для типов
variable
иapi.call
. Может быть, кто-нибудь с большим опытом C ++ сможет объяснить; возможно, это была мера всесторонней защиты, а не гарантия.источник
if
или&&
, но использование!!
может помочь в некоторых компиляторах, если оноif (!!(number & mask))
заменено наbit triggered = !!(number & mask); if (triggered)
; на некоторых встроенных компиляторах с битовыми типами присвоение, например, 256 битовому типу даст ноль. Без него!!
кажущееся безопасное преобразование (копированиеif
условия в переменную и последующее ветвление) не будет безопасным.Может, программисты думали примерно так ...
!! myAnswer является логическим. В контексте, это должно стать логическим, но я просто люблю грохнуть, чтобы убедиться, потому что однажды была таинственная ошибка, которая меня укусила, и ба-бах, я ее убил.
источник
Это может быть примером трюка двойного взрыва , подробнее см . Идиома Safe Bool . Резюмирую первую страницу статьи.
В C ++ существует несколько способов предоставления логических тестов для классов.
Мы можем протестировать класс,
Однако
opereator bool
считается небезопасным, поскольку допускает бессмысленные операции, такие какtest << 1;
илиint i=test
.Реализация тривиальна,
Два идиоматических способа проверки
Testable
объекта:Первая версия
if (!!test)
- это то, что некоторые называют трюком двойного взрыва .источник
explicit operator bool
для предотвращения неявного преобразования в другие целочисленные типы.