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

Permite que una función acepte cualquier número de argumentos adicionales.

Una función es variádica si el último parámetro de su lista de parámetros es una elipsis ( ... ).

La coma que precede a los puntos suspensivos puede omitirse. (obsoleto en C++26)
// la función declarada de la siguiente manera
int printx(const char* fmt, ...);
int printx(const char* fmt...); // igual que la anterior, pero obsoleta desde C++26
// puede ser llamada con uno o más argumentos:
printx("hello world");
printx("a=%d b=%d", a, b);
int printy(..., const char* fmt); // error: ... solo puede ser el último parámetro
int printz(...); // válido, pero los argumentos no pueden accederse de forma portable

Esto es diferente de una expansión de parameter pack de función, que se indica mediante puntos suspensivos que forman parte de un declarador de parámetro, en lugar de puntos suspensivos que son un parámetro por sí solos. Tanto la expansión de parameter pack como los puntos suspensivos "variádicos" pueden aparecer en la declaración de una plantilla de función, como en el caso de std::is_function .

(since C++11)

Contenidos

Promociones predeterminadas de argumentos

Cuando se llama a una función variádica, después de las conversiones de lvalue-a-rvalue, array-a-puntero y función-a-puntero conversions , cada argumento que forma parte de la lista de argumentos variables sufre conversiones adicionales conocidas como default argument promotions :

(desde C++11)

Tipos de clase no-POD (hasta C++11) Enumeraciones con ámbito y tipos de clase con un constructor de copia no trivial elegible, un constructor de movimiento no trivial elegible, o un destructor no trivial (desde C++11) están condicionalmente soportados en llamadas potencialmente evaluadas con semántica definida por la implementación (estos tipos siempre están soportados en llamadas no evaluadas ).

Debido a que los parámetros variádicos tienen el rango más bajo para el propósito de resolución de sobrecarga , comúnmente se utilizan como respaldo general en SFINAE .

Dentro del cuerpo de una función que utiliza argumentos variádicos, los valores de estos argumentos pueden accederse utilizando las <cstdarg> facilidades de la biblioteca :

Definido en el encabezado <cstdarg>
habilita el acceso a los argumentos de función variádicos
(macro de función)
accede al siguiente argumento de función variádico
(macro de función)
(C++11)
realiza una copia de los argumentos de función variádicos
(macro de función)
finaliza el recorrido de los argumentos de función variádicos
(macro de función)
contiene la información necesaria para va_start , va_arg , va_end , y va_copy
(typedef)

El comportamiento de la macro va_start es indefinido si el último parámetro antes de los puntos suspensivos tiene tipo de referencia, o tiene un tipo que no es compatible con el tipo que resulta de las promociones de argumentos por defecto.

Si una expansión de paquete o una entidad resultante de una captura lambda se utiliza como el último parámetro en va_start , el programa está mal formado, no se requiere diagnóstico.

(since C++11)

Alternativas

  • Variadic templates también pueden utilizarse para crear funciones que toman un número variable de argumentos. A menudo son la mejor opción porque no imponen restricciones sobre los tipos de los argumentos, no realizan promociones de tipos enteros y de punto flotante, y son type safe.
  • Si todos los argumentos variables comparten un tipo común, un std::initializer_list proporciona un mecanismo conveniente (aunque con una sintaxis diferente) para acceder a argumentos variables. Sin embargo, en este caso los argumentos no pueden modificarse ya que std::initializer_list solo puede proporcionar un puntero const a sus elementos.
(desde C++11)

Notas

En el lenguaje de programación C hasta C23, al menos un parámetro nombrado debe aparecer antes del parámetro de elipsis, por lo que R printz ( ... ) ; no es válido hasta C23. En C++, esta forma está permitida aunque los argumentos pasados a dicha función no sean accesibles, y se utiliza comúnmente como la sobrecarga de respaldo en SFINAE , aprovechando la prioridad más baja de la conversión de elipsis en overload resolution .

Esta sintaxis para argumentos variádicos fue introducida en C++ de 1983 sin la coma antes de la elipsis. Cuando C89 adoptó los prototipos de función de C++, reemplazó la sintaxis con una que requiere la coma. Por compatibilidad, C++98 acepta tanto el estilo C++ f ( int n... ) como el estilo C f ( int n, ... ) . La gramática original de estilo C++ está obsoleta desde C++26.

La coma puede utilizarse en plantillas de función abreviadas para hacer que la elipsis signifique una función variádica en lugar de una plantilla variádica:

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

(since C++20)

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.

DR Se aplica a Comportamiento publicado Comportamiento correcto
CWG 506 C++98 pasar argumentos de clase no-POD a una
elipsis resultaba en comportamiento indefinido
pasar dichos argumentos es
condicionalmente soportado con
semántica definida por la implementación
CWG 634 C++98 los tipos de clase condicionalmente soportados
impedían el funcionamiento de algunos idioms SFINAE
siempre soportado si no se evalúa
CWG 2247 C++11 no había restricción sobre pasar paquetes de parámetros
o capturas de lambda a va_start
se considera incorrecto,
no se requiere diagnóstico
CWG 2347 C++11 no estaba claro si las enumeraciones con ámbito pasadas a
una elipsis están sujetas a promociones de argumentos por defecto
pasar enumeraciones con ámbito
es condicionalmente soportado con
semántica definida por la implementación

Véase también

Documentación de C para Argumentos variádicos
Documentación de C para Conversiones implícitas