sintaxis - C++, declaración de variables en la expresión ''if''
tipos de variables en c++ pdf (8)
A partir de C ++ 17, lo que intentabas hacer es finalmente posible :
if (int a = Func1(), b = Func2(); a && b)
{
// Do stuff with a and b.
}
Tenga en cuenta el uso de ;
de en lugar de ,
para separar la declaración y la condición real.
¿Que está pasando 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.
}
La sección 6.4.3 de la norma 2003 amplía cómo las variables declaradas en una condición de declaración de selección tienen alcance que se extiende hasta el final de las subestaciones controladas por la condición. Pero no veo dónde dice nada acerca de no poder poner paréntesis alrededor de la declaración, ni dice nada acerca de una sola declaración por condición.
Esta limitación es molesta incluso en los casos en que solo se requiere una declaración en la condición. Considera esto.
bool a = false, b = true;
if(bool x = a || b)
{
}
Si deseo ingresar el ámbito del cuerpo "si" con x establecido en falso, entonces la declaración necesita paréntesis (ya que el operador de asignación tiene una precedencia menor que el OR lógico), pero como el paréntesis no se puede usar, requiere la declaración de x afuera el cuerpo, filtrando esa declaración a un alcance mayor que el deseado. Obviamente, este ejemplo es trivial, pero un caso más realista sería aquel en que a y b son funciones que devuelven valores que deben ser probados
Entonces, ¿qué es lo que quiero hacer que no cumpla con el estándar o mi compilador está destruyendo mis bolas (VS2008)?
Aquí hay una solución fea utilizando un bucle (si ambas variables son números enteros):
#include <iostream>
int func1()
{
return 4;
}
int func2()
{
return 23;
}
int main()
{
for (int a = func1(), b = func2(), i = 0;
i == 0 && a && b; i++)
{
std::cout << "a = " << a << std::endl;
std::cout << "b = " << b << std::endl;
}
return 0;
}
Pero esto confundirá a otros programadores y es un código bastante malo, por lo que no es recomendable.
Un bloque {}
encerramiento simple (como ya se recomendó) es mucho más fácil de leer:
{
int a = func1();
int b = func2();
if (a && b)
{
std::cout << "a = " << a << std::endl;
std::cout << "b = " << b << std::endl;
}
}
Con un poco de magia de plantilla, puede solucionar el problema de no poder declarar múltiples variables:
#include <stdio.h>
template <class LHS, class RHS>
struct And_t {
LHS lhs;
RHS rhs;
operator bool () {
bool b_lhs(lhs);
bool b_rhs(rhs);
return b_lhs && b_rhs;
}
};
template <class LHS, class RHS>
And_t<LHS, RHS> And(const LHS& lhs, const RHS& rhs) { return {lhs, rhs}; }
template <class LHS, class RHS>
struct Or_t {
LHS lhs;
RHS rhs;
operator bool () {
bool b_lhs(lhs);
bool b_rhs(rhs);
return b_lhs || b_rhs;
}
};
template <class LHS, class RHS>
Or_t<LHS, RHS> Or(const LHS& lhs, const RHS& rhs) { return {lhs, rhs}; }
int main() {
if (auto i = And(1, Or(0, 3))) {
printf("%d %d %d/n", i.lhs, i.rhs.lhs, i.rhs.rhs);
}
return 0;
}
(Nota, esto pierde la evaluación de cortocircuito.)
Creo que ya insinuó el problema. ¿Qué debería hacer el compilador con este código?
if (!((1 == 0) && (bool a = false))) {
// what is "a" initialized to?
El operador "&&" es un cortocircuito lógico AND. Eso significa que si la primera parte (1==0)
resulta ser falsa, entonces la segunda parte (bool a = false)
no debe evaluarse porque ya se sabe que la respuesta final será falsa. Si (bool a = false)
no se evalúa, ¿qué hacer con el código más adelante que utiliza a
? ¿No podríamos inicializar la variable y dejarla indefinida? ¿Lo inicializaríamos con el valor predeterminado? ¿Qué pasa si el tipo de datos es una clase y hacer esto tiene efectos secundarios indeseables? ¿Qué bool
si en lugar de bool
utiliza una clase y no tiene un constructor predeterminado para que el usuario debe proporcionar los parámetros? ¿Qué hacemos entonces?
Aquí hay otro ejemplo:
class Test {
public:
// note that no default constructor is provided and user MUST
// provide some value for parameter "p"
Test(int p);
}
if (!((1 == 0) && (Test a = Test(5)))) {
// now what do we do?! what is "a" set to?
Parece que la limitación que ha encontrado parece perfectamente razonable: evita que ocurran este tipo de ambigüedades.
La última sección ya funciona, solo tienes que escribirla ligeramente diferente:
if (int a = Func1())
{
if (int b = Func2())
{
// do stuff with a and b
}
}
La condición en una instrucción if
o while
puede ser una expresión o una sola declaración de variable (con inicialización).
Su segundo y tercer ejemplo no son expresiones válidas, ni declaraciones válidas, ya que una declaración no puede formar parte de una expresión. Si bien sería útil poder escribir código como su tercer ejemplo, requeriría un cambio significativo en la sintaxis del lenguaje.
No veo dónde dice nada acerca de no poder poner paréntesis alrededor de la declaración, ni dice nada acerca de una sola declaración por condición.
La especificación de sintaxis en 6.4 / 1 da lo siguiente para la condición:
condition:
expression
type-specifier-seq declarator = assignment-expression
especificando una sola declaración, sin paréntesis u otros adornos.
Si desea encerrar variables en un ámbito más estrecho, siempre puede usar { }
adicional
//just use { and }
{
bool a = false, b = true;
if(bool x = a || b)
{
//...
}
}//a and b are out of scope
Una cosa a tener en cuenta, también es que las expresiones dentro del bloque if más grande
if (!((1 == 0) && (bool a = false)))
no necesariamente se garantiza que se evalúen de izquierda a derecha. Un error bastante sutil que tuve en el día tenía que ver con el hecho de que el compilador realmente estaba probando de derecha a izquierda en lugar de izquierda a derecha.