Sí, pero es probable que reciba otra advertencia.
La forma estándar de hacerlo es: (void)iid;
.
muy técnicamente, esto todavía podría cargar iid
en un registro y no hacer nada. De acuerdo, eso es extremadamente estúpido en la parte de compiladores (dudo que alguno lo haga, si elimina el compilador), pero es un problema más serio si la expresión que se ignora es algo relacionado con el comportamiento observable, como las llamadas a funciones IO o el lectura y escritura de variables volatile
.
Esto plantea una pregunta interesante: ¿Podemos tomar una expresión y completamente ignorarlo?
Es decir, lo que tenemos ahora es la siguiente:
#define USE(x) (void)(x)
// use iid in an expression to get rid of warning, but have no observable effect
USE(iid);
// hm, result of expression is gone but expression is still evaluated
USE(std::cout << "hmmm" << std::endl);
Esto se acerca a una solución:
// sizeof doesn't evaluate the expression
#define USE(x) (void)(sizeof(x))
Pero falla con:
void foo();
// oops, cannot take sizeof void
USE(foo());
La solución es simplemente:
// use expression as sub-expression,
// then make type of full expression int, discard result
#define USE(x) (void)(sizeof((x), 0))
Lo que garantiza que no hay operación.
Editar: Lo anterior garantiza de hecho ningún efecto, pero he publicado sin pruebas. Tras la prueba, genera una advertencia nuevamente, al menos en MSVC 2010, porque el valor no se utiliza. ¡Eso no es bueno, es hora de más trucos!
Recordatorio: Queremos "usar" una expresión sin evaluarla.¿Cómo puede hacerse esto? De esta manera:
#define USE(x) ((void)(true ? 0 : (x)))
Esto tiene un problema simple como la última vez (peor en realidad), en la que (x)
requiere de un simple convertible en int
. Esto es, de nuevo, trivial de arreglar:
#define USE(x) ((void)(true ? 0 : ((x), 0)))
Y estamos de vuelta a la misma clase de efecto que tenía la última vez (ninguno), pero esta vez se x
"utilizado" por lo que no obtenemos ninguna advertencia . ¿Bien hecho?
En realidad, hay todavía un problema con esta solución (y estuvo presente en la última solución de la ONU, así, pero pasó desapercibido), y se trata en este ejemplo:
struct foo {};
void operator,(const foo&, int) {}
foo f;
USE(f); // oops, void isn't convertible to int!
Es decir, si el tipo de la expresión (x)
sobrecarga el operador de coma a algo no convertible a int
, la solución falla. Por supuesto, poco probable, pero en aras de ir por la borda por completo, podemos fijarlo con:
#define USE(x) ((void)(true ? 0 : ((x), void(), 0)))
para asegurarse de que realmente terminamos con cero. This trick brought to you by Johannes.
También como se ha señalado, si lo anterior no fuera suficiente, un compilador lo suficientemente estúpida podría potencialmente "carga" la expresión 0
(en un registro o algo así), entonces no tenerlo en cuenta.
Creo que es imposible deshacerse de eso, ya que finalmente necesitamos una expresión para dar como resultado un tipo de algún tipo para ignorar, pero si alguna vez lo pienso lo agregaré.
¿No activará esto una advertencia de "declaración no tiene ningún efecto"? – falstro
@roe: No funciona en Visual C++. Tal vez lo haga en algunos otros compiladores. – sharptooth
Si entre la declaración y la declaración se abusa del preprocesador, podría tener un efecto. Por ejemplo '#define variableName exit (-1)' – Benoit