Étant donné une fonction en C++ avec des arguments qui ne sont que des types et n'ont pas d'identificateurs,
void foo1(int, int, int){cout << "called foo1";}
Je peux l'appeler ainsi:
int main()
{
foo1(10, 10, 10);
}
Pourquoi est-ce une construction valide en C++? Est-ce juste une idiosyncrasie de C++, ou ce type de déclaration a-t-il réellement un but? Pouvons-nous réellement accéder aux arguments qui ont été transmis d'une manière ou d'une autre? (Ce type de déclaration de méthode ne fonctionnera pas en Java.)
Considérons un cas où vous devez fournir une fonction qui répond au prototype suivant
void dostuff(int x, int y, int z);
Et dites que vous travaillez dans un espace 2D et n'utilisez pas z
dans votre implémentation. Vous pouvez
void dostuff(int x, int y, int z)
{
// use x and y
}
et ignorez simplement z
, mais le compilateur détectera probablement que vous avez défini mais pas utilisé z
et vous avertira que vous pourriez faire une erreur. Au lieu de cela, vous pouvez
void dostuff(int x, int y, int )
{
// use x and y
}
et omettez la définition de z
. Le compilateur accepte et supprime silencieusement le troisième paramètre car il sait que vous ne le souhaitez pas.
Vous ne voulez pas simplement désactiver l'avertissement en raison d'erreurs comme celle-ci
void dostuff(int x, int y, int z)
{
for (int z = 0; z < MAX; z++)
{
// use x and y and z, the local z.
}
}
Où un index de boucle mal nommé masque le paramètre z
. L'entrée de l'appelant est maintenant ignorée et cela pourrait avoir de graves conséquences. Cette erreur est souvent difficile à repérer avec le globe oculaire de marque 1, surtout si le z
local est enterré quelque part au fond d'une fonction complexe.
Chaque fois que le compilateur peut éliminer un bogue possible dans votre code, profitez-en. Cela signifie moins de travail pour vous.
Une déclaration comme
void foo1(int, int, int){cout << "called foo1";}
indique clairement dans la déclaration que vous souhaitez remplir une exigence avec votre fonction - par ex. remplacer une fonction spécifique dans la classe ou l'interface de base, qui par exemple pourrait y être déclaré
virtual void foo1(int something, int another, int andAnother) = 0;
MAIS vous n'avez pas l'intention d'utiliser les paramètres qui vous sont remis.
Un autre exemple serait si vous souhaitez remettre la fonction à par exemple une autre fonction qui attend un pointeur de fonction vers une fonction void avec trois paramètres int.
void giveMeFoo( void (*fn)(int, int, int) ) { ... }
De plus, des niveaux d'avertissement plus élevés émettent un avertissement, si des paramètres sont déclarés, qui ne sont pas évalués dans le corps de la fonction. Vous pouvez éviter cela en laissant de côté les noms des paramètres.
Les paramètres sans nom ne sont alors en effet plus accessibles dans le corps de la fonction - exprès. user4581301 a bien décrit pourquoi.
Déclarer une fonction autonome sans nom de paramètre comme dans votre exemple est autorisé en raison des utilisations décrites ci-dessus, mais cela n'a évidemment aucun sens dans la plupart des cas. Un exemple où cela a du sens est dans la section des commentaires. Un autre exemple de fonction autonome sans nom de paramètre pourrait être, si vous écrivez une bibliothèque et que vous souhaitez conserver la compatibilité descendante (votre fonction de bibliothèque n'a plus besoin du paramètre, mais vous ne voulez pas casser la déclaration d'en-tête publique) ou vous souhaitez réserver un paramètre pour une utilisation future.
Oui. C'est légal en C++.
C++ 11 n3337 standard 8.4.1 (p6) Définitions des fonctions:
Remarque: les paramètres inutilisés n'ont pas besoin d'être nommés. Par exemple,
void print(int a, int) { std::printf("a = %d\n", a); }
Norme C++ 14:
[8.3.5.11] n identifiant peut éventuellement être fourni comme nom de paramètre; s'il est présent dans une définition de fonction, il nomme un paramètre (parfois appelé "argument formel"). [Remarque: en particulier, paramètre les noms sont également facultatifs dans les définitions de fonction et les noms utilisés pour un paramètre dans différentes déclarations et la définition d'une fonction ne doit pas nécessairement être la même.]
C'est légal, et si vous vous demandez pourquoi:
En règle générale, les arguments sans nom proviennent de la simplification du code ou de la planification à l'avance des extensions. Dans les deux cas, laisser l'argument en place, bien qu'inutilisé, garantit que les appelants ne sont pas affectés par le changement.
Extrait de: Bjarne Stroustrup. "Le langage de programmation C++, quatrième édition."
L'idée est que vous pourriez vouloir changer la définition de la fonction pour utiliser l'espace réservé plus tard, sans changer tout le code où la fonction est appelée.
Les arguments dans une déclaration de fonction peuvent être déclarés sans identificateurs. Lorsque ceux-ci sont utilisés avec des arguments par défaut, cela peut sembler un peu drôle. Vous pouvez vous retrouver avec:
void f(int x, int = 0, float = 1.1);
En C++, vous n'avez pas besoin d'identifiants dans la définition de fonction, soit:
void f(int x, int, float flt) { /* ... */ }
Dans le corps de la fonction, x
et flt peuvent être référencés, mais pas l'argument du milieu, car il n'a pas de nom. Les appels de fonction doivent toujours fournir une valeur pour l'espace réservé, cependant: f(1)
ou f(1,2,3.0)
. Cette syntaxe vous permet de placer l'argument en tant qu'espace réservé sans l'utiliser.