Parámetro no utilizado en c ++ 11

79

En c ++ 03 y versiones anteriores, para deshabilitar la advertencia del compilador sobre parámetros no utilizados, generalmente uso dicho código:

#define UNUSED(expr) do { (void)(expr); } while (0)

Por ejemplo

int main(int argc, char *argv[])
{
    UNUSED(argc);
    UNUSED(argv);

    return 0;
}

Pero las macros no son las mejores prácticas para c ++, entonces. ¿Aparece alguna solución mejor con el estándar c ++ 11? Quiero decir, ¿puedo deshacerme de las macros?

¡Gracias por todo!

inkooboo
fuente
11
Por supuesto. Apague la advertencia.
Pete Becker
65
¡No! ¡No hagas eso!
Lightness Races in Orbit
9
¿Cuánto mejor es esa macro que expandirla en línea? (void)argc;es más corto y claro queUNUSED(argc);
David Rodríguez - dribeas
22
Me gusta unused(argc, argv)con template<class... T> void unused(T&&...){}. Claro, conciso y sin macros.
Xeo
19
@MadScientist, pero puede dejar un argumento sin nombre, o incluso simplemente comentar su nombre. void foo(int /*unused_arg*/, int used_arg)
kassak

Respuestas:

41

He usado una función con un cuerpo vacío para ese propósito:

template <typename T>
void ignore(T &&)
{ }

void f(int a, int b)
{
  ignore(a);
  ignore(b);
  return;
}

Espero que cualquier compilador serio optimice la llamada a la función y me silencie las advertencias.

Científico loco
fuente
20
Cuando Tes un parámetro de plantilla, T&&es una referencia universal que se une a cualquier cosa.
Angew ya no está orgulloso de SO
4
+1 Aunque la versión avanzada de Xeo de su comentario ni siquiera se menciona.
Christian Rau
12
¿Por qué ignorar el método incorporado? Simplemente omita el nombre del parámetro.
Jack Aidley
27
-1, esto es ridículo y un artilugio innecesario, especialmente cuando puede simplemente omitir el nombre del parámetro. Francamente, me molesta que esto tenga 25 votos a favor de alguna manera.
TC1
5
@ TC1 Esto hace que su código sea explícito sobre lo que hace y por qué. Tener parámetros o variables no utilizados es un olor en su código y esto lo hace explícito. Desactivar la advertencia hace que su código huela más.
dascandy
205

Puede simplemente omitir los nombres de los parámetros:

int main(int, char *[])
{

    return 0;
}

Y en el caso de main, incluso puede omitir los parámetros por completo:

int main()
{
    // no return implies return 0;
}

Consulte "§ 3.6 Inicio y terminación" en el estándar C ++ 11.

Henrik
fuente
12
Y en el caso de main, puede omitir los parámetros por completo. Y la returndeclaración, para el caso.
Mike Seymour
4
@MikeSeymour De hecho, considero que es una buena práctica omitir la declaración de devolución.
jtepe
6
@jotep Está bien, morderé. ¿Por qué lo considera una buena práctica?
Peter Wood
6
Casi siempre omito main's return 0en un caso de prueba, pero casi siempre escribo la auto-documentación return EXIT_SUCCESSen código de producción. ¡Esa es una buena práctica!
Lightness Races in Orbit
30
Esta me parece la mejor respuesta: cualquier cosa que se mezcle con macros o plantillas aún no garantiza que la variable no se pueda usar después. Esto silencia la advertencia y garantiza que el parámetro (sin nombre) no se pueda usar nunca.
Alnitak
51

Está <tuple>en C ++ 11 , que incluye el std::ignoreobjeto listo para usar , que nos permite escribir (muy probablemente sin imponer gastos generales de ejecución):

void f(int x)
{
    std::ignore = x;
}
Tomilov Anatoliy
fuente
4
Teniendo en cuenta que esto está en la biblioteca estándar y, por lo tanto, no implica tener que escribir funciones personalizadas, ¡diría que esta es la mejor solución!
BrainStone
2
Esta clase está "diseñada para usarse con std :: tie al desempaquetar un std :: tuple", no para este caso de uso. Diría que es una solución, pero probablemente no sea la mejor.
Maestro
1
Me gusta esto ignorarlo en realidad .. Ofc, si puedes eliminar el parámetro, elimina esto en su lugar (esa sería la mejor solución en todos los casos).
danger89
33

Para "deshabilitar" esta advertencia, lo mejor es evitar escribir el argumento, simplemente escriba el tipo.

void function( int, int )
{
}

o si lo prefieres coméntalo:

void function( int /*a*/, int /*b*/ )
{
}

Puede mezclar argumentos con nombre y sin nombre:

void function( int a, int /*b*/ )
{
}

Con C ++ 17 tiene el especificador de atributo [[maybe_unused]], como:

void function( [[maybe_unused]] int a, [[maybe_unused]] int b )
{
}
Nikko
fuente
2
Solía ​​hacer esto, pero rápidamente se convierte en una molestia ya que ya no se pueden comentar grandes fragmentos de código con/* ... */
Ponkadoodle
1
Es cierto, pero con los IDE modernos, supongo que si selecciona un bloque para comentarlo automáticamente, agregará un montón de "//" al comienzo de cada línea. Eso es lo que hace Eclipse CDT. Personalmente, solo uso el primer ejemplo sin nombre. (puede poner nombres en las declaraciones en un archivo .h, por ejemplo).
Nikko
5
@Wallacoloo Cuando quiero comentar una gran parte del código, uso #if 0 ... #endif, que pueden anidarse y nunca entrar en conflicto con los comentarios / * ... * / existentes.
Dmitry Frank
1
@DmitryFrank Y la mayoría de los editores e IDE admiten la atenuación de los #if 0bloques como un caso especial, incluso si no admiten intellisense de preprocesador completo.
Thomas
30

Nada equivalente, no.

Así que estás atascado con las mismas opciones de siempre. ¿Está contento de omitir los nombres en la lista de parámetros por completo?

int main(int, char**)

En el caso específico de main, por supuesto, simplemente podría omitir los parámetros en sí:

int main()

También existen los trucos típicos específicos de la implementación, como los de GCC __attribute__((unused)).

Carreras de ligereza en órbita
fuente
14

Las macros pueden no ser ideales, pero hacen un buen trabajo para este propósito en particular. Yo diría que siga usando la macro.

Mats Petersson
fuente
6
+1: En este caso, no causan ningún daño y resuelven un problema. No veo ninguna razón (más allá del ridículo mantra sin fundamento de "nunca uses una macro") para no emplearlos aquí.
Lightness Races in Orbit
1
¿Cuál es el beneficio de una macro sobre omitir el nombre del parámetro por completo?
Micha Wiedenmann
1
@MichaWiedenmann: Algunos parámetros solo se pueden usar cuando se establecen algunas constantes de preprocesamiento (normalmente, en Debug).
Matthieu M.
2
@MatthieuM .: Yo llamaría a la macro MAYBE_UNUSED, por esa razón; Por lo general, no me importa si he dicho "no se preocupe si no uso esto a continuación", pero continúe haciéndolo de todos modos.
Lightness Races in Orbit
2
Bien, entonces lo correcto probablemente sea llamarlo "HIDE_UNUSED_WARNING". Pero sigo pensando que usar una macro aquí es una idea perfectamente válida. Siempre que la macro se nombre de tal manera que no cause confusión y / o conflictos con otro código.
Mats Petersson
13

¿Qué tienes en contra de la forma antigua y estándar?

void f(int a, int b)
{
  (void)a;
  (void)b;
  return;
}
jcayzac
fuente
Encuentro que algunos compiladores están contentos con esto, pero algunos compiladores son más exigentes que otros. El trabajo multiplataforma debe probarse en todos los sistemas operativos y compiladores específicos para asegurarse de que todos estén contentos con la solución.
Jesse Chisholm
12

No hay nada nuevo disponible.

Lo que me funciona mejor es comentar el nombre del parámetro en la implementación. De esa manera, se deshace de la advertencia, pero aún conserva alguna noción de cuál es el parámetro (ya que el nombre está disponible).

Su macro (y cualquier otro enfoque de conversión a vacío) tiene la desventaja de que realmente puede usar el parámetro después de usar la macro. Esto puede hacer que el código sea más difícil de mantener.

Angew ya no está orgulloso de SO
fuente
12

El encabezado Boost <boost/core/ignore_unused.hpp>(Boost> = 1.56) define, para este propósito, la plantilla de función boost::ignore_unused().

int fun(int foo, int bar)
{
  boost::ignore_unused(bar);
#ifdef ENABLE_DEBUG_OUTPUT
  if (foo < bar)
    std::cerr << "warning! foo < bar";
#endif

  return foo + 2;
}

PS C ++ 17 tiene el [[maybe_unused]]atributo de suprimir advertencias sobre entidades no utilizadas.

manlio
fuente
1
[[maybe_unused]]es de forma explícita, actualmente la mejor.
Tomilov Anatoliy
0

Realmente me gusta usar macros para esto, porque le permite un mejor control cuando tiene diferentes compilaciones de depuración (por ejemplo, si desea compilar con afirmaciones habilitadas):

#if defined(ENABLE_ASSERTS)
  #define MY_ASSERT(x) assert(x)
#else
  #define MY_ASSERT(x)
#end

#define MY_UNUSED(x)

#if defined(ENABLE_ASSERTS)
  #define MY_USED_FOR_ASSERTS(x) x
#else
  #define MY_USED_FOR_ASSERTS(x) MY_UNUSED(x)
#end

y luego úsalo como:

int myFunc(int myInt, float MY_USED_FOR_ASSERTS(myFloat), char MY_UNUSED(myChar))
{
  MY_ASSERT(myChar < 12.0f);
  return myInt;
}
steeveeet
fuente
0

Tengo mi propia implementación para segmentos de código de tiempo crítico. He estado investigando por un tiempo un código de tiempo crítico para ralentizar y he descubierto que esta implementación consume alrededor del 2% del código de tiempo crítico que he optimizado:

#define UTILITY_UNUSED(exp) (void)(exp)
#define UTILITY_UNUSED2(e0, e1) UTILITY_UNUSED(e0); UTILITY_UNUSED(e1)
#define ASSERT_EQ(v1, v2) { UTILITY_UNUSED2(v1, v2); } (void)0

El código de tiempo crítico ha utilizado las ASSERT*definiciones con fines de depuración, pero en el lanzamiento claramente se ha cortado, pero ... Parece que este produce un código un poco más rápido en Visual Studio 2015 Update 3:

#define UTILITY_UNUSED(exp) (void)(false ? (false ? ((void)(exp)) : (void)0) : (void)0)
#define UTILITY_UNUSED2(e0, e1) (void)(false ? (false ? ((void)(e0), (void)(e1)) : (void)0) : (void)0)

La razón es doble false ? expresión. De alguna manera produce un código un poco más rápido en el lanzamiento con la máxima optimización.

No sé por qué esto es más rápido (parece un error en la optimización del compilador), pero al menos es una mejor solución para ese caso de código.

Nota : Lo más importante aquí es que un código de tiempo crítico se ralentiza sin las afirmaciones anteriores o macros no utilizadas en el lanzamiento. En otras palabras, la doble false ?expresión ayuda sorprendentemente a optimizar un código.

Andry
fuente
-1

windows.h define UNREFERENCED_PARAMETER :

#define UNREFERENCED_PARAMETER(P) {(P) = (P);}

Entonces podrías hacerlo así:

#include <windows.h>
#include <stdio.h>
int main(int argc, char **argv) {
  UNREFERENCED_PARAMETER(argc);
  puts(argv[1]);
  return 0;
}

O fuera de Windows:

#include <stdio.h>
#define UNREFERENCED_PARAMETER(P) {(P) = (P);}
int main(int argc, char **argv) {
  UNREFERENCED_PARAMETER(argc);
  puts(argv[1]);
  return 0;
}

fuente
6
Ésta no es una muy buena opción, porque operator=puede tener efectos secundarios.
Tamás Szelei