Зачем использовать!! при преобразовании int в bool?

Что может быть причиной преобразования целого числа в логическое значение таким образом?

bool booleanValue = !!integerValue;

вместо

bool booleanValue = integerValue;

Все, что я знаю, это то, что в VС++ 7 последнее вызовет предупреждение C4800, а первое не будет. Есть ли другая разница между ними?

Ответ 1

Проблемы с "!!" идиома заключается в том, что она красная, трудно различимая, легко ошибочно принята за опечатку, легко отбросить одну из "!" и т.д. Я помещал его в категорию "посмотрите, как мило, мы можем быть с C/С++".

Просто напишите bool isNonZero = (integerValue != 0);... ясно.

Ответ 2

Исторически, идиома !! использовалась для обеспечения того, чтобы ваш bool действительно содержал одно из двух значений, ожидаемых в переменной bool -like, поскольку C и С++ не имели истинного типа bool, и мы подделал его с помощью int s. Это сейчас проблема с "реальным" bool s.

Но использование !! является эффективным средством документирования (как для компилятора, так и для любых будущих людей, работающих в вашем коде), что да, вы действительно намеревались использовать этот int для bool.

Ответ 3

Потому что! integerValue означает integerValue == 0 и!! integerValue, значит, integerValue!= 0, действительное выражение, возвращающее bool. Последний - это литье с потерей информации.

Ответ 4

Он используется, потому что язык C (и некоторые предварительные стандартные компиляторы С++ тоже) не имел типа bool, просто int. Таким образом, int были использованы для представления логических значений: 0 должен был означать false, а все остальное было true. Оператор ! возвращал 1 из 0 и 0 из всего остального. Двойной ! использовался для инвертирования данных, и он должен был убедиться, что это значение равно 0 или 1 в зависимости от его логического значения.

В С++, начиная с введения правильного типа bool, больше не нужно этого делать. Но вы не можете просто обновлять все устаревшие источники, и вам не придется этого делать из-за обратной совместимости C с С++ (большую часть времени). Но многие люди по-прежнему делают это по той же причине: оставить свой код обратно совместимым со старыми компиляторами, которые до сих пор не понимают bool s.

И это единственный реальный ответ. Другие ответы вводят в заблуждение.

Ответ 5

Другим вариантом является тернарный оператор, который, как представляется, генерирует одну строку меньше кода сборки (в любом случае в Visual Studio 2005):

bool ternary_test = ( int_val == 0 ) ? false : true;

который создает код сборки:

cmp DWORD PTR _int_val$[ebp], 0
setne   al
mov BYTE PTR _ternary_test$[ebp], al

Versus:

bool not_equal_test = ( int_val != 0 );

который производит:

xor eax, eax
cmp DWORD PTR _int_val$[ebp], 0
setne   al
mov BYTE PTR _not_equal_test$[ebp], al

Я знаю, что это не огромная разница, но мне было любопытно, и я просто подумал, что поделюсь своими выводами.

Ответ 6

Bool может иметь только два состояния: 0 и 1. Целое число может иметь любое состояние от -2147483648 до 2147483647 при условии, что это 32-битное целое число. Унарный! операционные выходы 1, если вход равен 0 и выдает 0, если входной сигнал есть что угодно, кроме 0. Итак! 0 = 1 и! 234 = 0. Второе! просто переключает выход так, что 0 становится 1 и 1 становится 0.

Итак, первое утверждение гарантирует, что booleanValue будет установлено равным либо 0, либо 1, и никаким другим значением, второе утверждение не будет.

Ответ 7

!! - это идиоматический способ преобразования в bool, и он работает, чтобы заткнуть компилятор Visual С++ глупого предупреждения о предполагаемой неэффективности такого преобразования.

По другим ответам и комментариям я вижу, что многие люди не знакомы с этой полезностью идиомы в программировании Windows. Это означает, что они не сделали серьезных программ Windows. И предположите, что то, с чем они столкнулись, является репрезентативным (это не так).

#include <iostream>
using namespace std;

int main( int argc, char* argv[] )
{
    bool const b = static_cast< bool >( argc );
    (void) argv;
    (void) b;
}
> [d:\dev\test]
> cl foo.cpp
foo.cpp
foo.cpp(6) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)

[d:\dev\test]
> _

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

Приветствия и hth.,

Ответ 8

Ответ пользователя143506 правильный, но для возможной проблемы с производительностью я сравнил возможности в asm:

return x;, return x != 0;, return !!x; и даже return boolean_cast<bool>(x) приводит к этому совершенному набору инструкций asm:

test    edi/ecx, edi/ecx
setne   al
ret

Это было протестировано для GCC 7.1 и MSVC 19 2017. (Только boolean_converter в MSVC 19 2017 приводит к большему количеству asm-кода, но это вызвано темпатизацией и структурами и может быть пренебречь с точки зрения производительности, потому что те же строки, что указаны выше, могут просто дублироваться для разных функций с одинаковым временем выполнения.)

Это означает: нет разницы в производительности.

PS: Этот boolean_cast использовался:

#define BOOL int
// primary template
template< class TargetT, class SourceT >
struct boolean_converter;

// full specialization
template< >
struct boolean_converter<bool, BOOL>
{
  static bool convert(BOOL b)
  {
    return b ? true : false;
  }
};

// Type your code here, or load an example.
template< class TargetT, class SourceT >
TargetT boolean_cast(SourceT b)
{
  typedef boolean_converter<TargetT, SourceT> converter_t;
  return converter_t::convert(b);
}

bool is_non_zero(int x) {
   return boolean_cast< bool >(x);
}

Ответ 9

Никакая большая причина, кроме параноика или крика через код, что его bool.

для компилятора, в конце концов, он не будет иметь разницы.

Ответ 10

Мне никогда не нравится этот метод преобразования в тип данных bool - он плохо пахнет!

Вместо этого мы используем удобный шаблон под названием boolean_cast найденный здесь. Это гибкое решение, более ясное в том, что он делает и может использовать следующее:

bool IsWindow = boolean_cast< bool >(::IsWindow(hWnd));