web-dev-qa-db-fra.com

std :: ignore pour ignorer la variable inutilisée

Est-ce une bonne approche pour utiliser std::ignore pour ignorer les variables inutilisées?

Supposons que j'ai une fonction comme celle-ci:

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

Informations supplémentaires

Il s'agit d'un exemple et certaines réponses suggèrent d'utiliser des variables anonymes . Mais comment pourrais-je le faire pour d'autres cas, comme:

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;
}
35
gaurav bharadwaj

Dans ce cas, n'écrivez simplement pas le nom de la variable:

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

@ La réponse de Hayt est bonne, mais utilise la dernière version de C++ qui n'est pas toujours disponible. Ne pas écrire le nom d'une variable est une ancienne convention pour dire à un compilateur que vous n'avez pas réellement besoin de la variable.

Pour une question mise à jour, j'irais pour une instance statique d'une classe avec l'initialisation nécessaire dans un constructeur. Je dis l'initialisation parce que la seule raison que je peux faire pour avoir une telle fonction est d'initialiser un objet 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;
}

Cette solution a un petit bonus: SomethingInitializer est compatible RAII. Ainsi, lorsque l'application se termine, le destructeur est appelé et il peut effectuer une désinitialisation.

Notez que ce compilateur sait que les classes peuvent faire quelque chose d'utile dans le constructeur et le destructeur, donc il ne se plaindra pas de la variable inutilisée.

41
Alexey Guseynov

std::ignore peut fonctionner mais il est destiné à être utilisé pour les tuples. Vous devez donc inclure l'en-tête Tuple et qui sait quelles opérations sont effectuées pour l'affectation. Cela peut également se casser dans une autre version c ++ car il n'a jamais été documenté pour être utilisé de cette façon.

Un meilleur moyen pour cela est l'attribut C++ 17 [[maybe_unused]]

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

Il place la déclaration directement dans la déclaration de variable, vous n'avez donc pas à la déclarer dans une ligne/instruction supplémentaire.

La même chose peut être utilisée pour les variables locales (et locales-statiques)

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

Et aussi pour bien d'autres:

Apparaît dans la déclaration d'une classe, d'un typedef, d'une variable, d'un membre de données non statique, d'une fonction, d'une énumération ou d'un énumérateur. Si le compilateur émet des avertissements sur les entités inutilisées, cet avertissement est supprimé pour toute entité déclarée peut-être inutilisée.

Voir http://en.cppreference.com/w/cpp/language/attributes

Quant aux personnes concernées que vous pouvez toujours utiliser les variables après les avoir déclarées inutilisées:

Oui, cela est possible mais (au moins avec clang), vous obtiendrez des avertissements si vous utilisez maybe_unused variables déclarées.

38
Hayt

std :: ignore n'était pas destiné à être utilisé à cette fin:

Un objet de type non spécifié tel que n'importe quelle valeur peut lui être affectée sans effet. Destiné à être utilisé avec std :: tie lors du déballage d'un std :: Tuple, en tant qu'espace réservé pour les arguments qui ne sont pas utilisés.


Je vous suggère de ne pas faire ce que vous pensez, car dans un grand projet réel, cela conduira à un code plus difficile à maintenir, où on regarderait le prototype d'une fonction, on verrait qu'il faut un argument int i, mais la fonction n'aurait pas besoin de cela en réalité - ne se sent pas bien, n'est-ce pas? :)

15
gsamaras

Comme alternative, sans supprimer i de la signature (comme certains outils de documentation peuvent l'exiger), il existe plusieurs façons de désactiver l'avertissement:

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

Ce n'est pas entièrement portable, mais cela fait taire l'avertissement sur la plupart des compilateurs.

La façon la plus simple est de créer une fonction dédiée pour cela:

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

puis

void func(int i)
{
   Unused(i); // Silent warning for unused variable
}
8
Jarod42

Je pense que vous avez un problème XY ici. Vous ne vous souciez pas vraiment de la façon d'ignorer les variables statiques; vous voulez juste appeler une fonction une fois (et une seule fois) de manière réentrante thread-safe.

À quoi je dis: avez-vous entendu parler de std::call_once? Vous devez réécrire votre méthode sous la forme

#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
Jacob Manaker

Une autre façon de procéder consiste à utiliser un type de retour de fin comme le suivant:

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

Si vous avez plusieurs variables, vous pouvez toutes les répertorier:

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

Et vous pouvez toujours déclarer votre type de retour préféré si void n'est pas ce que vous voulez:

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

Les avantages de cette solution sont:

  • Le nom de la variable est conservé: comme mentionné par d'autres, ne pas donner de nom à la variable ne pourrait pas être une option (à cause de votre système de documentation, par exemple).

  • Vous ne polluerez pas votre corps de fonction avec des expressions inutiles visant à faire taire quelques avertissements.

  • Vous n'avez pas à définir explicitement la fonction de support pour ce faire.

Bien sûr, cela ne s'applique pas aux variables statiques déclarées dans le corps de la fonction, mais vous pouvez faire quelque chose de similaire lors du retour de la fonction (juste un exemple):

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

int main () {}

Plus ou moins les mêmes avantages.

1
skypjack