Namespaces
Variants

Variadic arguments

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Permet à une fonction d'accepter n'importe quel nombre d'arguments supplémentaires.

Une fonction est variadique si le dernier paramètre de sa liste de paramètres est une ellipse ( ... ).

La virgule précédant les points de suspension peut être omise. (obsolète en C++26)
// la fonction déclarée comme suit
int printx(const char* fmt, ...);
int printx(const char* fmt...); // identique à ci-dessus, mais obsolète depuis C++26
// peut être appelée avec un ou plusieurs arguments :
printx("hello world");
printx("a=%d b=%d", a, b);
int printy(..., const char* fmt); // erreur : ... ne peut être que le dernier paramètre
int printz(...); // valide, mais les arguments ne peuvent être accédés de manière portable

Ceci est différent d'une expansion de parameter pack de fonction, qui est indiquée par des points de suspension faisant partie d'un déclarateur de paramètre, plutôt que par des points de suspension seuls comme paramètre. L'expansion de parameter pack et les points de suspension « variadiques » peuvent tous deux apparaître dans la déclaration d'un modèle de fonction, comme dans le cas de std::is_function .

(depuis C++11)

Table des matières

Promotions d'arguments par défaut

Lorsqu'une fonction variadique est appelée, après les conversions lvalue-en-rvalue, tableau-en-pointeur et fonction-en-pointeur conversions , chaque argument faisant partie de la liste d'arguments variables subit des conversions supplémentaires appelées promotions d'arguments par défaut :

(depuis C++11)

Types de classes non-POD (jusqu'à C++11) Énumérations scopées et types de classes avec un constructeur de copie non trivial éligible, un constructeur de déplacement non trivial éligible, ou un destructeur non trivial (depuis C++11) sont conditionnellement pris en charge dans les appels potentiellement évalués avec une sémantique définie par l'implémentation (ces types sont toujours pris en charge dans les appels non évalués ).

Parce que les paramètres variadiques ont le rang le plus bas pour l'objectif de la résolution de surcharge , ils sont couramment utilisés comme solutions de repli universelles dans SFINAE .

Dans le corps d'une fonction utilisant des arguments variadiques, les valeurs de ces arguments peuvent être accédées en utilisant les <cstdarg> facilités de la bibliothèque :

Défini dans l'en-tête <cstdarg>
permet l'accès aux arguments des fonctions variadiques
(macro de fonction)
accède au prochain argument de fonction variadique
(macro de fonction)
(C++11)
effectue une copie des arguments de fonction variadiques
(macro de fonction)
termine le parcours des arguments de fonction variadiques
(macro de fonction)
contient les informations nécessaires pour va_start , va_arg , va_end , et va_copy
(typedef)

Le comportement de la macro va_start est indéfini si le dernier paramètre avant les points de suspension est de type référence, ou s'il est d'un type qui n'est pas compatible avec le type résultant des promotions d'arguments par défaut.

Si une expansion de paquet ou une entité résultant d'une capture lambda est utilisée comme dernier paramètre dans va_start , le programme est mal formé, aucun diagnostic requis.

(depuis C++11)

Alternatives

  • Les templates variadiques peuvent également être utilisés pour créer des fonctions qui prennent un nombre variable d'arguments. Ils constituent souvent le meilleur choix car ils n'imposent aucune restriction sur les types des arguments, n'effectuent pas de promotions entières et flottantes, et sont sûrs au niveau des types.
  • Si tous les arguments variables partagent un type commun, un std::initializer_list fournit un mécanisme pratique (bien qu'avec une syntaxe différente) pour accéder aux arguments variables. Dans ce cas cependant, les arguments ne peuvent pas être modifiés car std::initializer_list ne peut fournir qu'un pointeur constant vers ses éléments.
(depuis C++11)

Notes

Dans le langage de programmation C jusqu'à C23, au moins un paramètre nommé doit apparaître avant le paramètre ellipsis, donc R printz ( ... ) ; n'est pas valide jusqu'à C23. En C++, cette forme est autorisée même si les arguments passés à une telle fonction ne sont pas accessibles, et est couramment utilisée comme surcharge de secours dans SFINAE , exploitant la priorité la plus faible de la conversion ellipsis dans la résolution de surcharge .

Cette syntaxe pour les arguments variadiques a été introduite en 1983 dans C++ sans la virgule avant les points de suspension. Lorsque C89 a adopté les prototypes de fonctions de C++, il a remplacé la syntaxe par une version exigeant la virgule. Pour la compatibilité, C++98 accepte à la fois le style C++ f ( int n... ) et le style C f ( int n, ... ) . La grammaire originale de style C++ est dépréciée depuis C++26.

La virgule peut être utilisée dans les modèles de fonction abrégés pour faire en sorte que les points de suspension signifient une fonction variadique au lieu d'un modèle variadique :

void f1 ( auto ... ) ; // same as template<class... Ts> void f3(Ts...)
void f2 ( auto , ... ) ; // same as template<class T> void f3(T, ...)

(depuis C++20)

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement tel que publié Comportement correct
CWG 506 C++98 passer des arguments de classe non-POD à une
ellipse entraînait un comportement indéfini
passer de tels arguments est
conditionnellement pris en charge avec
une sémantique définie par l'implémentation
CWG 634 C++98 les types de classe conditionnellement pris en charge
empêchaient certains idiomes SFINAE de fonctionner
toujours pris en charge si non évalué
CWG 2247 C++11 aucune restriction sur le passage d'un pack de paramètres
ou d'une capture lambda à va_start
rendu incorrect,
aucun diagnostic requis
CWG 2347 C++11 il n'était pas clair si les énumérations scopées passées à
une ellipse étaient soumises aux promotions d'arguments par défaut
passer des énumérations scopées
est conditionnellement pris en charge avec
une sémantique définie par l'implémentation

Voir aussi

Documentation C pour Arguments variadiques
Documentation C pour Conversions implicites