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

Позволяет функции принимать любое количество дополнительных аргументов.

Функция является вариативной, если последний параметр в её списке параметров является многоточием ( ... ).

Запятая перед многоточием может быть опущена. (устарело в C++26)
// функция объявлена следующим образом
int printx(const char* fmt, ...);
int printx(const char* fmt...); // аналогично предыдущему, но устарело с C++26
// может быть вызвана с одним или более аргументами:
printx("hello world");
printx("a=%d b=%d", a, b);
int printy(..., const char* fmt); // ошибка: ... может быть только последним параметром
int printz(...); // корректно, но аргументы не могут быть переносимо доступны

Это отличается от раскрытия parameter pack функции, которое обозначается многоточием, являющимся частью декларатора параметра, а не многоточием как самостоятельным параметром. Как раскрытие parameter pack, так и «вариативное» многоточие могут встречаться в объявлении шаблона функции, как в случае с std::is_function .

(since C++11)

Содержание

Продвижения аргументов по умолчанию

При вызове вариативной функции, после преобразований lvalue-в-rvalue, массива-в-указатель и функции-в-указатель conversions , каждый аргумент, являющийся частью списка переменных аргументов, подвергается дополнительным преобразованиям, известным как default argument promotions :

(начиная с C++11)

Не-POD классы (до C++11) Scoped перечисления и классы с подходящим нетривиальным конструктором копирования, подходящим нетривиальным конструктором перемещения или нетривиальным деструктором (начиная с C++11) условно поддерживаются в потенциально вычисляемых вызовах с семантикой, определяемой реализацией (эти типы всегда поддерживаются в невычисляемых вызовах ).

Поскольку вариадические параметры имеют самый низкий приоритет для целей overload resolution , они обычно используются как универсальные резервные варианты в SFINAE .

В теле функции, использующей переменное количество аргументов, значения этих аргументов могут быть доступны с помощью <cstdarg> библиотечных средств :

Определено в заголовочном файле <cstdarg>
обеспечивает доступ к аргументам вариативной функции
(функция-макрос)
получает доступ к следующему аргументу вариативной функции
(функция-макрос)
(C++11)
создает копию аргументов вариативной функции
(функция-макрос)
завершает обход аргументов вариативной функции
(функция-макрос)
содержит информацию, необходимую для работы va_start , va_arg , va_end и va_copy
(определение типа)

Поведение макроса va_start не определено, если последний параметр перед многоточием имеет ссылочный тип, или имеет тип, который не совместим с типом, получающимся в результате стандартных приведений аргументов.

Если расширение пакета или сущность, полученная в результате захвата лямбда-выражения , используется в качестве последнего параметра в va_start , программа является некорректной, диагностика не требуется.

(since C++11)

Альтернативы

  • Вариативные шаблоны также могут использоваться для создания функций, принимающих переменное количество аргументов. Они часто являются лучшим выбором, поскольку не накладывают ограничений на типы аргументов, не выполняют целочисленные и плавающие преобразования и являются типобезопасными.
  • Если все переменные аргументы имеют общий тип, std::initializer_list предоставляет удобный механизм (хотя и с другим синтаксисом) для доступа к переменным аргументам. Однако в этом случае аргументы не могут быть изменены, поскольку std::initializer_list может предоставлять только константный указатель на свои элементы.
(начиная с C++11)

Примечания

В языке программирования C до стандарта C23 по крайней мере один именованный параметр должен предшествовать параметру с многоточием, поэтому R printz ( ... ) ; не является допустимым до C23. В C++ такая форма разрешена, даже если аргументы, передаваемые такой функции, недоступны, и обычно используется как резервная перегрузка в SFINAE , используя наименьший приоритет преобразования с многоточием в разрешении перегрузки .

Этот синтаксис для вариативных аргументов был введён в C++ 1983 года без запятой перед многоточием. Когда C89 заимствовал прототипы функций из C++, он заменил синтаксис на требующий запятую. Для совместимости C++98 принимает как C++-стиль f ( int n... ) так и C-стиль f ( int n, ... ) . Исходная грамматика в C++-стиле устарела начиная с C++26.

Запятая может использоваться в сокращенных шаблонах функций, чтобы заставить многоточие обозначать вариативную функцию вместо вариативного шаблона:

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)

Отчеты о дефектах

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.

DR Applied to Behavior as published Correct behavior
CWG 506 C++98 передача аргументов не-POD классов в
эллипсис приводила к неопределённому поведению
передача таких аргументов является
условно-поддерживаемой с
определяемой реализацией семантикой
CWG 634 C++98 условно-поддерживаемые классовые типы
нарушали работу некоторых идиом SFINAE
всегда поддерживаются, если не вычисляются
CWG 2247 C++11 отсутствовали ограничения на передачу параметр-пака
или захвата лямбды в va_start
сделано некорректным,
диагностика не требуется
CWG 2347 C++11 было неясно, подлежат ли ограниченные перечисления, передаваемые в
эллипсис, стандартным продвижениям аргументов
передача ограниченных перечислений
является условно-поддерживаемой с
определяемой реализацией семантикой

Смотрите также

C documentation для Variadic arguments
C documentation для Implicit conversions