Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

passer une liste d'argument variable lors d'un appel

36 réponses
Avatar
superbabar51
Bonjour,

Comment est t-il possible de passer une liste d'argument variable =E0
une autre fonction?

Par exemple, considerons la fonction handle_error suivante:

void handle_error (int errorcode, std::string format, ...)
{
printf(format.c_str(), ...)
// o=F9 ... repr=E9sente les arguments pass=E9s =E0 handle_error
}

Est-ce possible (proprement)?

Merci

10 réponses

1 2 3 4
Avatar
Michel Decima
Bonjour,

Comment est t-il possible de passer une liste d'argument variable à
une autre fonction?

Par exemple, considerons la fonction handle_error suivante:

void handle_error (int errorcode, std::string format, ...)
{
printf(format.c_str(), ...)
// où ... représente les arguments passés à handle_error
}

Est-ce possible (proprement)?


voir les fonctions vprintf, vsprintf et vsnprintf, et <stdarg.h>

De memoire:

void handle_error (int errorcode, std::string format, ...)
{
va_list ap;
va_start(ap, format);
vprintf(format.c_str(), ap);
va_end(ap);
}

Il faut donner a va_start le nom du dernier argument avant la liste
des arguments variables (donc ici format). Je ne sais pas si ca marche
avec un std::string, j'utilise toujours un char const* dans ce genre
de fonctions, et je sais qu'il y a des restrictions sur les types
qu'on peut passer dans les ...

Avatar
Cyrille
Bonjour,

Comment est t-il possible de passer une liste d'argument variable à
une autre fonction?


Les listes d'arguments variables sont gérables en utilisant std::va_list
fourni par l'en-tête <cstdarg> et les macros va_start et va_end.
Pour les passer à une fonction, il faut que celle-ci accepte un
paramètre std::va_list. On ne peut pas simplement passer à la fonction à
arguments variables.

Pour std::printf, par exemple, il y a la fonction std::vprintf, dont le
prototype est:
int vprintf(const char *format, va_list ap);

Ta fonction handle_error s'écrirait donc ainsi:

using namespace std;

void handle_error ( int errorcode, string format, ... )
{
va_list args;
va_start( args, format.c_str() );
vprintf( format.c_str(), args );
va_end( args );
}

--
Sukuuru Ranburu For Ever

Avatar
Michel Decima

void handle_error ( int errorcode, string format, ... )
{
va_list args;
va_start( args, format.c_str() );
vprintf( format.c_str(), args );
va_end( args );
}



pourquoi utiliser c_str() dans l'appel a va_start ?

Avatar
Cyrille

void handle_error ( int errorcode, string format, ... )
{
va_list args;
va_start( args, format.c_str() );
vprintf( format.c_str(), args );
va_end( args );
}



pourquoi utiliser c_str() dans l'appel a va_start ?


Pour rien, c'est une erreur.

--
Sukuuru Ranburu For Ever


Avatar
Loïc Joly
Bonjour,

Comment est t-il possible de passer une liste d'argument variable à
une autre fonction?

Par exemple, considerons la fonction handle_error suivante:

void handle_error (int errorcode, std::string format, ...)
{
printf(format.c_str(), ...)
// où ... représente les arguments passés à handle_error
}

Est-ce possible (proprement)?


Souvent, en C++, on préfère chaîner les appels. Un truc du style :

handleError(errorCode, format).arg("Toto").arg(12).arg("Toto3")

Ou, avec la surcharge d'opérateurs :

handleError(errorCode, format) << "Toto" << 12 << "Toto3";

--
Loïc

Avatar
John Deuf
Loïc Joly :

Est-ce possible (proprement)?


Souvent, en C++, on préfère chaîner les appels. Un truc du style :
handleError(errorCode, format).arg("Toto").arg(12).arg("Toto3")


Tout a fait. Exemple ici :
http://c.developpez.com/faq/cpp/?page=fonctions#CLASS_chainage_appels

--
John Deuf


Avatar
Sylvain
Loïc Joly wrote on 08/04/2006 20:55:

Souvent, en C++, on préfère chaîner les appels. Un truc du style :

handleError(errorCode, format).arg("Toto").arg(12).arg("Toto3")

Ou, avec la surcharge d'opérateurs :

handleError(errorCode, format) << "Toto" << 12 << "Toto3";



je crains que "en C++" signifie ici "pour un exercice de style".

si l'error handler en question ne fait qu'écrire l'information reçue
dans un fichier (stream, console, ...), cela peut fonctionner.

mais, même dans ce cas, si le gestionnaire d'erreur va jusqu'à arrêter
l'application (selon la sévérité de l'erreur) seul le premier argument
sera enregistré.

si, pour un autre mode, la méthode affiche un dialogue d'alerte, cela va
être un peu moins efficace (une alerte par argument!) (à moins de
recompliquer arbitrairement le gestionnaire avec des inputters muets et
un flusher bavard).

je pense qu'il est préférable de garder des objets spécialisés: utiliser
un (char) stream avec sa famille d'opérateurs d'injection d'un coté,
concevoir un gestionnaire d'erreur de l'autre; vouloir mettre l'usage de
l'un dans l'autre est source de duplication de code et ne parait pas
vraiment utile ni efficace.

Sylvain.

Avatar
superbabar51
Merci à tous!
Avatar
James Kanze
Sylvain wrote:
Loïc Joly wrote on 08/04/2006 20:55:


Souvent, en C++, on préfère chaîner les appels. Un truc du style :



handleError(errorCode, format).arg("Toto").arg(12).arg("Toto3")



Ou, avec la surcharge d'opérateurs :



handleError(errorCode, format) << "Toto" << 12 << "Toto3";



je crains que "en C++" signifie ici "pour un exercice de style".


C'est plus que pour un exércise de style. En C++, on ne peut pas
passer des types non POD à des varargs. Ce qui les rend à peu
près inutilisables.

si l'error handler en question ne fait qu'écrire l'information
reçue dans un fichier (stream, console, ...), cela peut
fonctionner.


mais, même dans ce cas, si le gestionnaire d'erreur va jusqu'à
arrêter l'application (selon la sévérité de l'erreur) seul le
premier argument sera enregistré.


Pas chez moi. Au moins, pas avec la forme avec des <<.

si, pour un autre mode, la méthode affiche un dialogue
d'alerte, cela va être un peu moins efficace (une alerte par
argument!) (à moins de recompliquer arbitrairement le
gestionnaire avec des inputters muets et un flusher bavard).


Encore une fois -- pas chez moi. Évidemment, dans mes
applications, il n'y a pas de dialogue d'alerte, parce que
normalement, il n'y a pas de terminal affecté au programme, mais
j'envoie bien des emails et d'autres choses semblables.

je pense qu'il est préférable de garder des objets
spécialisés: utiliser un (char) stream avec sa famille
d'opérateurs d'injection d'un coté, concevoir un gestionnaire
d'erreur de l'autre;


C'est effectivement une solution simple et efficace. Si on
s'arrête à la gestion des erreurs, je ne vois pas besoin de plus
non plus.

Dans mon cas, j'avais à gérer un système plus complète de
logging, où il fallait bien rendre l'utilisation la plus simple
possible, pour qu'il soit réelement utilisé partout.

vouloir mettre l'usage de l'un dans l'autre est source de
duplication de code et ne parait pas vraiment utile ni
efficace.


Je ne sais pas en ce qui concerne l'efficacité -- il a été assez
efficace pour les applications où je m'en suis servi. En
revanche, je ne vois pas ton point en ce qui concerne la
duplication du code -- les templates sont là pour ça.

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34


Avatar
Sylvain
James Kanze wrote on 09/04/2006 20:35:
si l'error handler en question ne fait qu'écrire l'information
reçue dans un fichier (stream, console, ...), cela peut
fonctionner.

mais, même dans ce cas, si le gestionnaire d'erreur va jusqu'à
arrêter l'application (selon la sévérité de l'erreur) seul le
premier argument sera enregistré.


Pas chez moi. Au moins, pas avec la forme avec des <<.


mais pas chez moi non plus mon brave monsieur!

non pas que je réserve l'instruction:
errorHdlr << "monTrucVachementPropreQuiSertAFlusher";
pour réaliser le traitement (vs la mise en tampon), mais juste que c'est
trop grotesque pour que je l'imagine.

si, pour un autre mode, la méthode affiche un dialogue
d'alerte, cela va être un peu moins efficace (une alerte par
argument!) (à moins de recompliquer arbitrairement le
gestionnaire avec des inputters muets et un flusher bavard).


Encore une fois -- pas chez moi. Évidemment, dans mes
applications, il n'y a pas de dialogue d'alerte, parce que
normalement, il n'y a pas de terminal affecté au programme, mais
j'envoie bien des emails et d'autres choses semblables.


je n'en doute pas un instant! j'ai bien vu des codes se connectant sur
une base, locker N tables, écrire *un* octet, delocker le bouzin, perdre
la connection, ..., pour chaque octet injecté; donc je ne m'étonnerai de
rien.

en ce qui concerne la
duplication du code -- les templates sont là pour ça.


excellente celle-là !! merci ! je la note en tête des histoires droles.

Sylvain.


1 2 3 4