web-dev-qa-db-fra.com

Paramètre inutilisé en c ++ 11

Dans c ++ 03 et versions antérieures, pour désactiver l'avertissement du compilateur à propos du paramètre inutilisé, j'utilise généralement ce code:

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

Par exemple 

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

    return 0;
}

Mais les macros ne sont pas la meilleure pratique pour c ++, donc . Une meilleure solution apparaît-elle avec le standard c ++ 11? Je veux dire, puis-je me débarrasser des macros?

Merci pour tout!

74
inkooboo

J'ai utilisé une fonction avec un corps vide à cette fin:

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

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

Je m'attends à ce que tout compilateur sérieux optimise l'appel de fonction et le fasse taire les alertes.

38
MadScientist

Vous pouvez simplement omettre les noms de paramètres:

int main(int, char *[])
{

    return 0;
}

Et dans le cas de main, vous pouvez même omettre complètement les paramètres:

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

Voir "§ 3.6 Début et fin" dans la norme C++ 11.

182
Henrik

Il y a le <Tuple> dans C++ 11, qui inclut l'objet std::ignore prêt à l'emploi, qui nous permet d'écrire (très probablement sans imposer de temps d'exécution supplémentaire):

void f(int x)
{
    std::ignore = x;
}
40
Orient

Rien d'équivalent, non.

Donc, vous êtes coincé avec les mêmes anciennes options. Souhaitez-vous omettre entièrement les noms dans la liste des paramètres?

int main(int, char**)

Dans le cas spécifique de main, bien sûr, vous pouvez simplement omettre les paramètres eux-mêmes:

int main()

Il existe également des astuces spécifiques à chaque implémentation, telles que __attribute__((unused)) de GCC.

Pour "désactiver" cet avertissement, le mieux est d'éviter d'écrire l'argument, il suffit d'écrire le type.

void function( int, int )
{
}

ou si vous préférez, commentez:

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

Vous pouvez mélanger des arguments nommés et non nommés:

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

Avec C++ 17 vous avez un spécificateur d'attribut [[peut-être_utilisé]], comme:

void function( [[maybe_unused]] int a, [[maybe_unused]] int b )
{
}
26
Nikko

Les macros ne sont peut-être pas idéales, mais elles font du bon travail dans ce but particulier. Je dirais qu'il faut s'en tenir à la macro.

14
Mats Petersson

Qu'est-ce que vous avez contre l'ancienne et la manière habituelle?

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

Il n'y a rien de nouveau disponible.

Ce qui me convient le mieux est de commenter le nom du paramètre dans l'implémentation. De cette façon, vous vous débarrassez de l'avertissement tout en conservant une notion du paramètre (puisque le nom est disponible).

Votre macro (et toutes les autres approches de conversion par conversion) présente l'inconvénient de pouvoir utiliser le paramètre après avoir utilisé la macro. Cela peut rendre le code plus difficile à maintenir.

12
Angew

L'en-tête Boost <boost/core/ignore_unused.hpp> (Boost> = 1.56) définit à cet effet le modèle de fonction 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 possède l'attribut [[maybe_unused]] pour supprimer les avertissements relatifs aux entités inutilisées.

11
manlio

J'aime beaucoup utiliser des macros pour cela, car cela vous permet de mieux contrôler les différentes versions de débogage (par exemple, si vous voulez créer avec des assertions activées):

#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

et ensuite l'utiliser comme:

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

J'ai ma propre implémentation pour les segments critiques de code . Je recherche depuis longtemps un code critique pour ralentir et j'ai constaté que cette implémentation consomme environ 2% du temps dont je dispose pour optimiser le code:

#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

Le code critique pour le temps a utilisé les définitions ASSERT* à des fins de débogage, mais il est clairement défini dans la version précédente, mais ... Semble que celui-ci produit un code un peu plus rapide dans 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 raison est en double expression false ?. En quelque sorte, il produit un code un peu plus rapide avec une optimisation maximale.

Je ne sais pas pourquoi c'est plus rapide (cela semble un bogue dans l'optimisation du compilateur), mais au moins une meilleure solution pour ce cas de code.

Remarque : La chose la plus importante ici est qu’un code à durée critique ralentit sans assertions ci-dessus ou macroses inutilisées en publication. En d'autres termes, la double expression false ? permet étonnamment d'optimiser un code.

0
Andry