O que está acontecendo aqui?
if(int a = Func1())
{
// Works.
}
if((int a = Func1()))
{
// Fails to compile.
}
if((int a = Func1())
&& (int b = Func2()))
)
{
// Do stuff with a and b.
// This is what I'd really like to be able to do.
}
A seção 6.4.3 no padrão de 2003 expõe como as variáveis declaradas em uma condição de instrução de seleção têm escopo que se estende até o final das subinstruções controladas pela condição. Mas não vejo onde diz algo sobre não ser capaz de colocar parênteses em torno da declaração, nem diz nada sobre apenas uma declaração por condição.
Essa limitação é irritante mesmo nos casos em que apenas uma declaração na condição é necessária. Considere isto.
bool a = false, b = true;
if(bool x = a || b)
{
}
Se eu quiser inserir o escopo de corpo 'if "com x definido como falso, então a declaração precisa de parênteses (uma vez que o operador de atribuição tem precedência menor do que o OR lógico), mas como o parêntese não pode ser usado, ele requer a declaração de x fora o corpo, vazando essa declaração para um escopo maior do que o desejado. Obviamente, este exemplo é trivial, mas um caso mais realista seria aquele em que aeb são funções que retornam valores que precisam ser testados
Então, o que eu quero fazer não está em conformidade com o padrão, ou meu compilador está me dando mal (VS2008)?
fonte
if
.if
não é um loop, é uma condicional.while
são as mesmas que paraif
.if (int a = foo(), int b = bar(), a && b)
:? Se o operador vírgula não estiver sobrecarregado, o padrão diz que as expressões são avaliadas da esquerda para a direita e o valor do resultado é a última expressão. Funciona comfor
inicialização de loops, por que não aqui?if
funciona, e parece ser uma suposição errada.Respostas:
A partir do C ++ 17, o que você estava tentando fazer finalmente é possível :
Observe o uso de
;
em vez de,
para separar a declaração e a condição real.fonte
Acho que você já insinuou o problema. O que o compilador deve fazer com este código?
O operador "&&" é um AND lógico de curto-circuito. Isso significa que, se a primeira parte
(1==0)
for falsa, a segunda parte(bool a = false)
não deve ser avaliada porque já se sabe que a resposta final será falsa. Se(bool a = false)
não for avaliado, o que fazer com o código mais tarde que usaa
? Será que não inicializaríamos a variável e deixá-la indefinida? Iríamos inicializá-lo com o padrão? E se o tipo de dados fosse uma classe e isso tivesse efeitos colaterais indesejáveis? E se em vez debool
você usar uma classe e ela não tiver um construtor padrão, de modo que o usuário deve fornecer parâmetros - o que fazemos então?Aqui está outro exemplo:
Parece que a limitação que você encontrou parece perfeitamente razoável - ela impede que esses tipos de ambigüidades aconteçam.
fonte
A condição em uma instrução
if
ouwhile
pode ser uma expressão ou uma declaração de variável única (com inicialização).Seu segundo e terceiro exemplos não são expressões válidas, nem declarações válidas, pois uma declaração não pode fazer parte de uma expressão. Embora seja útil ser capaz de escrever código como o seu terceiro exemplo, isso exigiria uma mudança significativa na sintaxe da linguagem.
A especificação de sintaxe em 6.4 / 1 fornece o seguinte para a condição:
especificando uma única declaração, sem parênteses ou outros adornos.
fonte
Se você deseja incluir variáveis em um escopo mais restrito, você sempre pode usar
{ }
fonte
A última seção já funciona, você só precisa escrever um pouco diferente:
fonte
Aqui está uma solução alternativa feia usando um loop (se ambas as variáveis forem inteiras):
Mas isso vai confundir outros programadores e é um código bastante ruim, então não é recomendado.
Um
{}
bloco envolvente simples (como já recomendado) é muito mais fácil de ler:fonte
Uma coisa a notar, também é que as expressões dentro do bloco if maior
não têm necessariamente a garantia de serem avaliados da esquerda para a direita. Um bug bastante sutil que tive naquela época tinha a ver com o fato de que o compilador estava testando da direita para a esquerda em vez de da esquerda para a direita.
fonte
if(p && p->str && *p->str) ...
. Da direita para a esquerda teria sido mortal e não sutil. Com outros operadores - até atribuição! - e argumentos de chamada de função você está certo, mas não com os operadores de curto-circuito.Com um pouco de magia de modelo, você pode meio que contornar o problema de não ser capaz de declarar várias variáveis:
(Observe, isso perde a avaliação de curto-circuito.)
fonte