Comment puis-je écrire une fonction qui accepte un nombre variable d'arguments? Est-ce possible, comment?
c++
variadic-functions
nunos
la source
la source
Réponses:
Vous ne devriez probablement pas, et vous pouvez probablement faire ce que vous voulez faire d'une manière plus sûre et plus simple. Techniquement, pour utiliser un nombre variable d'arguments en C, vous incluez stdarg.h. De là, vous obtiendrez le
va_list
type ainsi que trois fonctions qui opèrent sur lui appeléva_start()
,va_arg()
etva_end()
.Si vous me demandez, c'est un gâchis. Cela a l'air mauvais, ce n'est pas sûr, et c'est plein de détails techniques qui n'ont rien à voir avec ce que vous essayez conceptuellement d'accomplir. Au lieu de cela, envisagez d'utiliser la surcharge ou l'héritage / polymorphisme, le modèle de générateur (comme dans les
operator<<()
flux) ou les arguments par défaut, etc. Ceux-ci sont tous plus sûrs: le compilateur en sait plus sur ce que vous essayez de faire, donc il y a plus d'occasions qu'il peut s'arrêter vous avant de vous couper la jambe.la source
...
syntaxe?printf()
, par exemple, la fonction analyse l'argument chaîne pour les jetons spéciaux pour déterminer le nombre d'arguments supplémentaires qu'elle devrait attendre dans la liste des arguments variables.<cstdarg>
en C ++ au lieu de<stdarg.h>
En C ++ 11, vous disposez de deux nouvelles options, comme l' indique la page de référence des fonctions Variadic dans la section Alternatives :
Voici un exemple montrant les deux alternatives ( voir en direct ):
Si vous utilisez
gcc
ouclang
nous pouvons utiliser la variable magique PRETTY_FUNCTION pour afficher la signature de type de la fonction qui peut être utile pour comprendre ce qui se passe. Par exemple en utilisant:donnerait les résultats suivants pour les fonctions variadiques dans l'exemple ( voir en direct ):
Dans Visual Studio, vous pouvez utiliser FUNCSIG .
Mettre à jour Pre C ++ 11
Avant C ++ 11, l'alternative pour std :: initializer_list serait std :: vector ou l'un des autres conteneurs standard :
et l'alternative pour les modèles variadic serait des fonctions variadic bien qu'elles ne soient pas sécuritaires pour le type et en général sujettes aux erreurs et puissent être dangereuses à utiliser, mais la seule autre alternative potentielle serait d'utiliser des arguments par défaut , bien que cela ait une utilisation limitée. L'exemple ci-dessous est une version modifiée de l'exemple de code dans la référence liée:
L'utilisation de fonctions variadiques s'accompagne également de restrictions dans les arguments que vous pouvez transmettre, qui sont détaillés dans le projet de norme C ++ dans la section
5.2.2
Appel de fonction paragraphe 7 :la source
typename
vs estclass
-elle intentionnelle ci-dessus? Si oui, veuillez expliquer.initializer_list
récursive?Une solution C ++ 17: sécurité complète + belle syntaxe d'appel
Depuis l'introduction des modèles variadiques en C ++ 11 et des expressions de repli en C ++ 17, il est possible de définir une fonction de modèle qui, sur le site de l'appelant, peut être appelée comme s'il s'agissait d'une fonction varidique mais avec les avantages de :
Voici un exemple pour les types d'arguments mixtes
Et un autre avec une correspondance de type forcée pour tous les arguments:
Plus d'information:
la source
template<class Head, class... Tail, class = std::enable_if_t<are_same<Head, Tail...>::value, void>>
Head
etTail...
sont les mêmes ", où " sont les mêmes " signifiestd::conjunction<std::is_same<Head, Tail>...>
. Lisez cette dernière définition comme "Head
est la même chose que toutTail...
".en c ++ 11 vous pouvez faire:
liste initialiseur FTW!
la source
En C ++ 11, il existe un moyen de faire des modèles d'arguments variables qui conduisent à un moyen vraiment élégant et sûr d'avoir des fonctions d'arguments variables. Bjarne lui-même donne un bel exemple de printf utilisant des modèles d'arguments variables dans le C ++ 11FAQ .
Personnellement, je considère cela si élégant que je ne m'embêterais même pas avec une fonction d'argument variable en C ++ jusqu'à ce que ce compilateur prenne en charge les modèles d'argument variable C ++ 11.
la source
,
opérateur avec des expressions de pli). Sinon, je ne pense pas.Les fonctions variadiques de style C sont prises en charge en C ++.
Cependant, la plupart des bibliothèques C ++ utilisent un idiome alternatif, par exemple, alors que la
'c' printf
fonction prend des arguments variables, l'c++ cout
objet utilise une<<
surcharge qui traite de la sécurité des types et des ADT (peut-être au détriment de la simplicité de mise en œuvre).la source
std::initializer_lists
... Et cela introduit déjà une complexité énorme sur une tâche simple.En dehors des varargs ou de la surcharge, vous pourriez envisager d'agréger vos arguments dans un std :: vector ou d'autres conteneurs (std :: map par exemple). Quelque chose comme ça:
De cette façon, vous gagneriez en sécurité de type et la signification logique de ces arguments variadiques serait évidente.
Certes, cette approche peut avoir des problèmes de performances, mais vous ne devriez pas vous en préoccuper à moins d'être sûr que vous ne pouvez pas en payer le prix. C'est une sorte d'approche "Pythonique" du c ++ ...
la source
La seule façon consiste à utiliser des arguments de variable de style C, comme décrit ici . Notez que ce n'est pas une pratique recommandée, car elle n'est pas sûre pour les types et sujette aux erreurs.
la source
Il n'y a aucun moyen C ++ standard de le faire sans recourir à varargs (
...
) de style C.Il y a bien sûr des arguments par défaut qui "ressemblent" à un nombre variable d'arguments selon le contexte:
Les quatre appels de fonction appellent
myfunc
avec un nombre variable d'arguments. Si aucun n'est fourni, les arguments par défaut sont utilisés. Notez cependant que vous ne pouvez omettre que les arguments de fin. Il n'y a aucun moyen, par exemple d'omettrei
et de donner uniquementj
.la source
Il est possible que vous souhaitiez une surcharge ou des paramètres par défaut - définissez la même fonction avec les paramètres par défaut:
Cela vous permettra d'appeler la méthode avec l'un des quatre appels différents:
... ou vous pourriez rechercher les conventions d'appel v_args de C.
la source
Si vous connaissez la plage de nombre d'arguments qui seront fournis, vous pouvez toujours utiliser une surcharge de fonction, comme
etc...
la source
Utilisation de modèles variadiques, exemple pour reproduire
console.log
comme vu en JavaScript:Nom de fichier, par exemple
js_console.h
:la source
Comme d'autres l'ont dit, les varargs de style C. Mais vous pouvez également faire quelque chose de similaire avec des arguments par défaut.
la source
C'est possible maintenant ... en utilisant boost any et des modèles Dans ce cas, le type d'arguments peut être mélangé
la source
Combinez les solutions C et C ++ pour l'option sémantiquement la plus simple, la plus performante et la plus dynamique. Si vous vous trompez, essayez autre chose.
L'utilisateur écrit:
Sémantiquement, cela ressemble et se sent exactement comme une fonction à n arguments. Sous le capot, vous pourriez le déballer dans un sens ou dans l'autre.
la source
Nous pourrions également utiliser un initializer_list si tous les arguments sont const et du même type
la source
Version simple
la source