Пространства имён
Варианты
Действия

Переменное число аргументов

Материал из cppreference.com
< cpp‎ | language
 
 
 
Функции
Общее
Категории значений (lvalue, rvalue, xvalue)
Порядок оценки (sequence points)
Константные выражения
Потенциально оцениваемые выражения
Первичные выражения
Лямбда-выражения(C++11)
Литералы
Целочисленные литералы
Литералы с плавающей запятой
Логические литералы
Символьные литералы включая управляющие последовательности
Строковые литералы
Литерал нулевого указателя(C++11)
Пользовательский литерал(C++11)
Операторы
a=b, a+=b, a-=b, a*=b, a/=b, a%=b, a&=b, a|=b, a^=b, a<<=b, a>>=b
++a, --a, a++, a--
+a, -a, a+b, a-b, a*b, a/b, a%b, ~a, a&b, a|b, a^b, a<<b, a>>b
a||b, a&&b, !a
a==b, a!=b, a<b, a>b, a<=b, a>=b, a<=>b(C++20)
a[b], *a, &a, a->b, a.b, a->*b, a.*b
a(...), a,b, a?b:c
Выражение new
Выражение delete
Выражение throw
alignof
sizeof
sizeof...(C++11)
typeid
noexcept(C++11)
Выражения свёртки(C++17)
Альтернативные представления операторов
Приоритет и ассоциативность
Перегрузка операторов
Сравнение по умолчанию(C++20)
Преобразования
Неявные преобразования
const_cast
static_cast
reinterpret_cast
dynamic_cast
Явные преобразования: (T)a, T(a)
Пользовательское преобразование
 

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

Обозначается конечным ... (кроме вводящего расширение пакета) (начиная с C++11), следующего за списком-параметров объявления функции.

Когда список-параметров не пуст, перед ... может стоять необязательная запятая, обозначающая функцию с переменным числом аргументов. Это обеспечивает совместимость с C (в котором добавлено требование к запятой, когда он получает прототипы функций из C++).

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

Примечание: это отличается от расширения пакета параметров функции, которое обозначается многоточием, которое является частью декларатора параметра, а не многоточием, которое появляется после всех объявлений параметров. Как расширение пакета параметров, так и "вариативное" многоточие могут появляться в объявлении шаблона фу��кции, как в случае std::is_function.

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

Содержание

[править] Преобразования по умолчанию

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

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

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

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

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

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

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

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

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

[править] Альтернативы

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

[править] Примечание

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

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

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

void f1(auto...); // то же, что и template<class... Ts> void f3(Ts...)
void f2(auto, ...); // то же, что и template<class T> void f3(T...)

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

[править] Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
CWG 506 C++98 передача аргументов класса, отличного от POD, в многоточие
приводила к неопределённому поведению
передача таких аргументов поддерживается
условно с семантикой, определяемой реализацией
CWG 634 C++98 условно-поддерживаемые типы классов сделали некоторые
идиомы SFINAE неработоспособными
всегда поддерживается, если не оценивается
CWG 2247 C++11 нет ограничений на передачу пакета параметров или
лямбда-захвата в va_start
сделано неправильным, диагностика не требуется
CWG 2347 C++11 было неясно, подлежат ли перечисления с областью
видимости, переданные многоточию, продвижению
аргументов по умолчанию
передача перечислений с областью видимости
поддерживается условно с семантикой,
определяемой реализацией

[править] Смотрите также

Документация C по Переменное число аргументов