c++ - std:: ignore por ignorar la variable no utilizada
c++11 download (6)
¿Es un buen enfoque utilizar 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;
}
Como alternativa, sin eliminar i
de la firma (ya que algunas herramientas de documentación pueden requerirlo), hay varias formas de silenciar la advertencia:
void func(int i)
{
static_cast<void>(i); // Silent warning for unused variable
}
No es totalmente portátil, pero 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 entonces
void func(int i)
{
Unused(i); // Silent warning for unused variable
}
Creo que tienes un problema XY aquí. Realmente no te importa cómo ignorar las variables estáticas; solo desea llamar a una función una vez (y solo una vez) de una manera segura y reentrante.
A lo que le digo: ¿has oído hablar de std::call_once
? Deberías reescribir tu 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);
}
En tal caso, simplemente no escriba el nombre de la variable:
void func(int /*i*/)
{
...
}
La respuesta de @ Hayt es buena, pero usa la última versión de C ++ que no siempre está disponible. No escribir nombre de variable es una vieja convención para decirle a un compilador que realmente no necesita la variable.
Para una pregunta actualizada, buscaría una instancia estática de una clase con la inicialización necesaria en un constructor. Digo inicialización porque la única razón por la que puedo hacer para tener dicha función es inicializar algún objeto global.
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. Entonces, cuando la aplicación termina, se llama al destructor y puede realizar la desinicialización.
Tenga en cuenta que el compilador sabe que las clases pueden hacer algo útil en constructor y destructor, por lo que no se quejará de la variable no utilizada.
Otra forma de hacerlo es mediante un tipo de devolución 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 mencionaron 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ás el cuerpo de tu 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.
std::ignore no fue pensado para ser utilizado con este propósito:
Un objeto de tipo no especificado tal que cualquier valor puede asignarse sin ningún efecto. Diseñado para uso con std :: tie al desempaquetar std :: tuple, como marcador de posición para los argumentos que no se usan.
Yo sugeriría que no hagas 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 eso en realidad, no se siente bien, ¿verdad? :)
std::ignore
puede funcionar, pero está destinado a ser utilizado para tuplas. Por lo tanto, debe incluir el encabezado de tupla y quién sabe qué operaciones se realizan para la asignación. Esto también puede romperse en otra versión de C ++ porque nunca se documentó su uso 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 puede usarse 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, un typedef, una variable, un miembro de datos no estático, una función, una enumeración o un enumerador. Si el compilador emite advertencias en las entidades no utilizadas, esa advertencia se suprime para cualquier entidad declarada tal vez sin usar.
Ver http://en.cppreference.com/w/cpp/language/attributes
En cuanto a las personas afectadas, todavía puede usar las variables después de declararlas sin usar:
Sí, esto es posible, pero (al menos con clang) recibirás advertencias en caso de que maybe_unused
variables declaradas maybe_unused
usar.