2012-01-22 8 views
16

Quizás me estoy poniendo oxidado (he estado escribiendo en Python recientemente).¿qué hay de malo en declarar una variable dentro de la condición de si?

¿Por qué no se compila?

if ((int i=f()) == 0) 

sin la () alrededor del int i=f() consigo otro, mucho más razonable de error de i no está siendo booleano. ¡Pero es por eso que quería el paréntesis en primer lugar!

Supongo que al usar los paréntesis se convierte en una expresión y las declaraciones de declaración no se permiten en una expresión. ¿Es tan? Y si es así, ¿es una de las peculiaridades de sintaxis de C++?

Por cierto, en realidad estaba tratando de hacer esto:

if ((Mymap::iterator it = m.find(name)) != m.end()) 
    return it->second; 
+1

¿Qué pasa? Todo –

+5

@VJovic - Vago si obtuviste tu puntaje de reputación con respuestas tan elaboradas y útiles;) – davka

+0

No, sería negativo;) Pero en serio, cualquier estándar de codificación normal prohíbe ese código oscuro. –

Respuesta

37

Puede declarar una variable en la instrucción if en C++, pero se limita a ser utilizado con la inicialización directa y tiene que convertir en un valor booleano:

if (int i = f()) { ... } 

C++ no tiene nada que pueda se describirá como "expresión de declaración", es decir, [sub-] expresiones que declaran una variable.

En realidad, Acabo de mirar la cláusula de la norma y las dos formas de inicialización están soportados de acuerdo con 6.4 [stmt.select] párrafo 1:

... 
condition: 
    expression 
    attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause 
    attribute-specifier-seqopt decl-specifier-seq declarator braced-init-list 
... 

Es decir, también se sea posible escribir :

if (int i{f()}) { ... } 

Obviamente, esto sólo funciona en C++ 2011 debido a C++ 2003 no tiene un aparato ortopédico-inicialización.

+0

No creo que su último ejemplo sea legal. Solo puede hacer 'if (int i {f()}) {/*...*/}' o 'if (int i = f()) {/*...*/}'. _braced-init-list_ debe incluir llaves. (_braced-init-list_ es "{_initializer-list_, OPT}" o "{}"). –

+0

@CharlesBailey: sí, tienes razón: de alguna manera confundí la "lista de inicios arriostrados" con la (...). Arreglaré esto. –

+0

gracias, suena razonable, y la respuesta de @Ilya a continuación da alguna explicación – davka

20

Hay un problema con el ámbito de aplicación.

Considere el siguiente código:

if ((int a = foo1()) || (int b = foo2())) 
{ 
    bar(b); 
} 

es B declaradas dentro del bloque? ¿Qué ocurre si foo1() devuelve verdadero?

+0

se olvidó de mencionar que no lo hago Creo que esto es un problema de alcance ya que '()' AFAIK no crea alcance. ¿Estoy equivocado? – davka

+3

@SoapBox, pero ¿y si foo1 devuelve 1 y por evaluación de cortocircuito (que está garantizado hasta donde yo sé) se salta la asignación de 'b'? – lccarrasco

+0

Exactamente: no puede proponer que se declaren las variables en() a menos que aborde el problema del alcance; las variables en C++ tienen un alcance que comienza cuando su declaración se 'ejecuta', lo que puede ocurrir que nunca ocurra en esta situación. – greggo

4

Puede declarar una variable en una instrucción if (o en para o while), pero solo en el bloque de paréntesis externo y debe ser capaz de convertirse a bool.

su conjetura es básicamente correcta, no es permitido porque

(int i = 42;) 

no es una declaración válida con la inicialización.

Es necesario una línea adicional,

Mymap::iterator it; 
if ((it = m.find(name)) != m.end()) 
    return it->second; 

pero entonces es mejor escribir

Mymap::iterator it = m.find(name); 
if (it != m.end()) 
    return it->second; 

Se puede retener la línea return después de la if, si realmente desea que esta línea de la espalda, por lo menos para mí esto no perjudica la legibilidad, pero otros pueden ver eso diferente.

Si realmente, realmente desea declarar un iterador y utilizar el bool como en una condición if, se podría hacer

if (struct { int it; operator bool() { return it != m.end; } } s = { m.find(name) }) 
    return s.it->second; 

pero me parece que es perjudicial ;-)

0

es verdad que no se puede escribir

if ((int i=f()) == 0) 

pero se puede escribir perfectamente

if (int i=f()) 

lo que puede utilizar el operador && para realizar ambas operaciones en una declaración como

if (int i=1 && (i=f()) == 0) 

i debe ser inicializado con un valor distinto de 0, y debe ser la primera condición si su compilador aplica izquierda evaluación a la derecha.

Desafortunadamente, eso no es aplicable en el caso de los iteradores como su segundo ejemplo pregunta.

Cuestiones relacionadas