Acabei de entrar em um projeto com uma enorme base de código.
Estou lidando principalmente com C ++ e grande parte do código que eles escrevem usa negação dupla para sua lógica booleana.
if (!!variable && (!!api.lookup("some-string"))) {
do_some_stuff();
}
Eu sei que esses caras são programadores inteligentes, é óbvio que não estão fazendo isso por acidente.
Não sou especialista em C ++ experiente, meu único palpite sobre o motivo pelo qual eles estão fazendo isso é que eles querem ter certeza absoluta de que o valor que está sendo avaliado é a representação booleana real. Então, eles negam e depois negam isso novamente para retornar ao seu valor booleano real.
Isso está correto ou estou faltando alguma coisa?
Respostas:
É um truque para converter em bool.
fonte
bool
tipo, para ajudar a evitar o armazenamento de valores diferentes de1
e0
em variáveis booleanas.!!
ou!=0
resolvendo o problema, e dentre os dois, encontro o limpador mais antigo (já que ele funcionará em uma quantidade maior de tipos). Também concordo que não há razão para usar o código em questão.Na verdade, é um idioma muito útil em alguns contextos. Pegue essas macros (exemplo do kernel do Linux). Para o GCC, eles são implementados da seguinte maneira:
Por que eles têm que fazer isso? O GCC
__builtin_expect
trata seus parâmetros comolong
não ebool
, portanto, precisa haver alguma forma de conversão. Como eles não sabem o quecond
é quando estão escrevendo essas macros, é mais geral simplesmente usar o!!
idioma.Provavelmente, eles poderiam fazer a mesma coisa comparando com 0, mas, na minha opinião, é mais simples fazer a negação dupla, já que é o mais próximo de um cast-to-bool que C possui.
Esse código também pode ser usado em C ++ ... é o menor denominador comum. Se possível, faça o que funciona em C e C ++.
fonte
Os codificadores pensam que ele converterá o operando em bool, mas como os operandos de && já estão implicitamente convertidos em bool, é totalmente redundante.
fonte
É uma técnica para evitar a escrita (variável! = 0) - ou seja, converter de qualquer tipo para um bool.
Um código IMO como esse não tem lugar em sistemas que precisam ser mantidos - porque não é um código imediatamente legível (daí a pergunta em primeiro lugar).
O código deve ser legível - caso contrário, você deixará um legado de dívida de tempo para o futuro - pois leva tempo para entender algo que é desnecessariamente complicado.
fonte
bool(expr)
: faz a coisa certa e todos entendem a intenção à primeira vista.!!(expr)
é uma dupla negação, que acidentalmente se converte em bool ... isso não é simples.Sim, está correto e não, você não está perdendo algo.
!!
é uma conversão para bool. Veja esta pergunta para mais discussão.fonte
Desvia um aviso do compilador. Tente o seguinte:
A linha 'bar' gera um "valor forçado para bool 'true' ou 'false' (aviso de desempenho)" no MSVC ++, mas a linha 'baz' foge bem.
fonte
bool
tipo - tudo é codificado como0
ou1
em umint
.É operador! sobrecarregado?
Caso contrário, eles provavelmente estão fazendo isso para converter a variável em um bool sem produzir um aviso. Definitivamente, essa não é uma maneira padrão de fazer as coisas.
fonte
Desenvolvedores legado C teve nenhum tipo booleano, para que eles muitas vezes
#define TRUE 1
e#define FALSE 0
em seguida utilizado tipos de dados numéricos arbitrários para comparações booleanas. Agora que temosbool
, muitos compiladores emitem avisos quando certos tipos de atribuições e comparações são feitas usando uma mistura de tipos numéricos e tipos booleanos. Esses dois usos acabarão colidindo ao trabalhar com código legado.Para contornar esse problema, alguns desenvolvedores usam a seguinte identidade booleana:
!num_value
retornabool true
ifnum_value == 0
;false
de outra forma.!!num_value
retornabool false
senum_value == 0
;true
de outra forma. O único negação é suficiente para converternum_value
abool
; no entanto, a dupla negação é necessária para restaurar o sentido original da expressão booleana.Esse padrão é conhecido como idioma , isto é, algo comumente usado por pessoas familiarizadas com o idioma. Portanto, não o vejo como um antipadrão, por mais que eu o visse
static_cast<bool>(num_value)
. O elenco pode muito bem dar os resultados corretos, mas alguns compiladores emitem um aviso de desempenho, então você ainda precisa resolver isso.A outra maneira de resolver isso é dizer
(num_value != FALSE)
,. Eu também estou bem com isso, mas, apesar de tudo,!!num_value
é muito menos detalhado, pode ser mais claro e não é confuso na segunda vez que você o vê.fonte
!!
foi usado para lidar com o C ++ original, que não tinha um tipo booleano (assim como o C).Problema de exemplo:
No interior
if(condition)
, ascondition
necessidades devem ser avaliadas para algum tipodouble, int, void*
, etc., mas nãobool
como ainda não existe.Digamos que exista uma classe
int256
(um número inteiro de 256 bits) e todas as conversões / conversões inteiras foram sobrecarregadas.Para testar se
x
era "verdadeiro" ou diferente de zero,if (x)
seria convertidox
em algum número inteiro e, em seguida, avaliaria seint
era diferente de zero. Uma sobrecarga típica de(int) x
retornaria apenas os LSbits dex
.if (x)
estava testando apenas os LSbits dex
.Mas o C ++ tem o
!
operador. Uma sobrecarga!x
normalmente avaliaria todos os bits dex
. Então, para voltar à lógica não invertida,if (!!x)
é usado.Ref As versões mais antigas do C ++ usaram o operador `int` de uma classe ao avaliar a condição em uma instrução` if () `?
fonte
Como Marcin mencionou, pode muito bem importar se a sobrecarga do operador está em jogo. Caso contrário, em C / C ++, não importa, exceto se você estiver executando uma das seguintes ações:
comparação direta com
true
(ou em C algo como umaTRUE
macro), que quase sempre é uma má idéia. Por exemplo:if (api.lookup("some-string") == true) {...}
você simplesmente deseja que algo seja convertido em um valor estrito de 0/1. Em C ++, uma atribuição a a
bool
fará isso implicitamente (para aquelas coisas que são implicitamente convertíveis embool
). Em C ou se você está lidando com uma variável não bool, esse é um idioma que eu já vi, mas prefiro a(some_variable != 0)
variedade.Eu acho que no contexto de uma expressão booleana maior, ela simplesmente atrapalha as coisas.
fonte
Se a variável for do tipo de objeto, pode ter um! operador definido, mas sem conversão para bool (ou pior, uma conversão implícita para int com diferentes semânticas. Chamar o operador! duas vezes resulta em uma conversão em bool que funciona mesmo em casos estranhos.
fonte
Está correto, mas em C não faz sentido aqui - 'if' e '&&' tratariam a expressão da mesma maneira sem o '!!'.
O motivo para fazer isso em C ++, suponho, é que '&&' pode estar sobrecarregado. Mas então, por isso poderia '!', Para que ele não realmente garantir-lhe obter um bool, sem olhar para o código para os tipos de
variable
eapi.call
. Talvez alguém com mais experiência em C ++ possa explicar; talvez seja uma medida de defesa em profundidade, não uma garantia.fonte
if
ou&&
, mas o uso!!
pode ajudar em alguns compiladores seif (!!(number & mask))
for substituído porbit triggered = !!(number & mask); if (triggered)
; em alguns compiladores incorporados com tipos de bits, atribuir, por exemplo, 256 a um tipo de bit, produzirá zero. Sem o!!
, a transformação aparentemente segura (copiar aif
condição para uma variável e depois ramificar) não será segura.Talvez os programadores estivessem pensando algo assim ...
!! myAnswer é booleano. No contexto, deve se tornar booleano, mas eu adoro bater coisas de bang para ter certeza, porque era uma vez um bug misterioso que me mordeu, e bang bang, eu o matei.
fonte
Este pode ser um exemplo do truque de golpe duplo , consulte The Safe Bool Idiom para obter mais detalhes. Aqui eu resumo a primeira página do artigo.
No C ++, existem várias maneiras de fornecer testes booleanos para classes.
Podemos testar a classe,
No entanto,
opereator bool
é considerado inseguro porque permite operações sem sentido, comotest << 1;
ouint i=test
.A implementação é trivial,
As duas maneiras idiomáticas de testar o
Testable
objeto sãoA primeira versão
if (!!test)
é o que algumas pessoas chamam de truque do golpe duplo .fonte
explicit operator bool
para impedir a conversão implícita em outros tipos integrais.