std::ignore para ignorar la variable no utilizada


¿Es un buen enfoque usar std::ignore para ignorar variables no utilizadas?

Supongamos que tengo una función como esta:

void func(int i)
{
   //for some reason, I don't need i anymore but I cannot change signature of function    
   std::ignore = i; 
}

Información Adicional

Este fue un ejemplo y algunas respuestas sugirieron usar variables anónimas. Pero ¿cómo lo haría para otros casos, como:

int Thread_UnSafe_func_returnSomething():
void func()
{
   // To make it thread safe
   // Also it is required to call only once
   static int i = Thread_UnSafe_func_returnSomething();

   std::ignore = i;
}
Author: Mailerdaimon, 2016-09-28

6 answers

En tal caso, simplemente no escriba el nombre de la variable:

void func(int /*i*/)
{
    ...
}

La respuesta de@Hayt es buena, pero utiliza la última versión de C++ que no siempre está disponible. No escribir nombre de variable es una antigua convención para decirle a un compilador que realmente no necesita la variable.

Para una pregunta actualizada iría por una instancia estática de una clase con inicialización necesaria en un constructor. Digo inicialización porque la única razón que puedo hacer para tener tal función es inicializar algunos global objeto.

class SomethingInitializer {
public:
    SomethingInitializer() {
        func_returnSomething();
    }
    ~SomethingInitializer() {
        // Note, that when you initialize something it is a good practice to deinitialize it at the end, and here is a proper place for that.
    }
};

void func() {
    static SomethingInitializer initializer;
}

Esta solución tiene una pequeña ventaja: SomethingInitializer es compatible con RAII. Así que cuando la aplicación termina destructor se llama y puede hacer deinitialización.

Tenga en cuenta que ese compilador sabe que las clases pueden hacer algo útil en constructor y destructor, por lo que no se quejará por la variable no utilizada.

 40
Author: Alexey Guseynov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-28 12:51:00

std::ignore puede funcionar, pero está destinado a ser utilizado para las tuplas. Por lo tanto, debe incluir el encabezado de la tupla y quién sabe qué operaciones se realizan para la asignación. Esto también puede romper en otra versión de c++ porque nunca fue documentado para ser utilizado de esa manera.

Una mejor manera para esto es el atributo C++17 [[maybe_unused]]

void func([[maybe_unused]] int i)
{
}

Coloca la declaración justo en la declaración de la variable, por lo que no tiene que declararla en una línea/declaración adicional.

Lo mismo se puede utilizar para variables locales (y locales estáticas)

...
[[maybe_unused]] static int a = something();
...

Y también para muchos más:

Aparece en la declaración de una clase, a typedef, a variable, a miembro de datos no estático, una función, una enumeración o un enumerador. Si el compilador emite advertencias sobre entidades no utilizadas, esa advertencia es suprimido para cualquier entidad declarada maybe_unused.

Véase http://en.cppreference.com/w/cpp/language/attributes

En cuanto a las personas interesadas que se puede sigue usando las variables después de declararlas sin usar:

Sí, esto es posible, pero (al menos con clang) obtendrá advertencias en caso de que use maybe_unused variables declaradas.

 35
Author: Hayt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-29 08:19:07

Std::ignore no estaba destinado a ser utilizado para este propósito:

Un objeto de tipo no especificado tal que se le puede asignar cualquier valor sin efecto. Diseñado para su uso con std::tie al desempaquetar una std:: tupla, como un marcador de posición para los argumentos que no se utilizan.


Te sugeriría no hacer lo que estás pensando, ya que en un gran proyecto del mundo real, conducirá a un código que es más difícil de mantener, donde uno miraría el prototipo de una función, vería que toma un argumento int i, pero la función no necesitaría que en realidad - no se siente bien, ¿verdad? :)

 15
Author: gsamaras,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-28 17:35:08

Como alternativa, sin quitar i de la firma (como algunas herramientas de documentación pueden requerirlo), hay varias maneras de silenciar la advertencia:

void func(int i)
{
   static_cast<void>(i); // Silent warning for unused variable
}

No es completamente portable, pero eso silencia la advertencia en la mayoría de los compiladores.

La manera limpia es crear una función dedicada para eso:

template <typename T>
void Unused(T&& /*No name*/) { /*Empty*/ }

Y luego

void func(int i)
{
   Unused(i); // Silent warning for unused variable
}
 8
Author: Jarod42,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-28 11:59:23

Creo que tienes un problema XY aquí. Realmente no te importa cómo ignorar las variables estáticas; solo quieres llamar a una función una vez (y solo una vez) de una manera reentrante y segura para subprocesos.

A lo que yo digo: ¿has oído hablar std::call_once? Debe reescribir su método como

#include <mutex>

int Thread_UnSafe_func_returnSomething();
void func(void)
{
      //To make it thread safe
     static std::once_flag initComplete;
     std::call_once(initComplete, func_returnSomething);
 }
 2
Author: Jacob Manaker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-28 16:14:02

Otra forma de hacerlo es por medio de un tipo de retorno final como el siguiente:

auto func(int i) -> decltype(void(i)) {}
int main() {}

Si tiene más de una variable, puede enumerarlas todas:

auto func(int i, int j) -> decltype(void(i), void(j)) {}
int main() {}

Y aún puede declarar su tipo de devolución preferido si void no es lo que desea:

auto func(int i) -> decltype(void(i), int{}) { return 42; }
int main() {}

Las ventajas de esta solución son:

  • El nombre de la variable se conserva: como han mencionado otros, no dar un nombre a la variable no podría ser una opción (debido a su sistema de documentación, como ejemplo).

  • No contaminará su cuerpo de función con expresiones inútiles destinadas a silenciar algunas advertencias.

  • No tiene que definir explícitamente la función de soporte para hacer eso.

Por supuesto, esto no se aplica a las variables estáticas declaradas en el cuerpo de la función, pero puede hacer algo similar al regresar de la función (solo un ejemplo):

int f() {
    static int i = 0;
    static int j = 0;
    return void(i), void(j), 42;
}

int main () {}

Más o menos las mismas ventajas.

 1
Author: skypjack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-28 17:53:35