Аргументы переменного числа
Позволяет функции принимать любое количество дополнительных аргументов.
Функция является функцией с переменным числом аргументов, если последний параметр её списка параметров — многоточие (...).
| Запятую перед многоточием можно опустить. | (устарело в C++26) |
// the function declared as follows
int printx(const char* fmt, ...);
int printx(const char* fmt...); // same as above, but deprecated since C++26
// may be called with one or more arguments:
printx("hello world");
printx("a=%d b=%d", a, b);
int printy(..., const char* fmt); // error: ... can only be the last parameter
int printz(...); // valid, but the arguments cannot be accessed portably
| Это отличается от раскрытия пакета параметров функции: оно обозначается многоточием, являющимся частью декларатора параметра, а не отдельным параметром в виде многоточия. И раскрытие пакета параметров, и многоточие «переменного числа аргументов» могут присутствовать в объявлении шаблона функции, как в случае | (начиная с C++11) |
Продвижения аргументов по умолчанию
При вызове функции с переменным числом аргументов после преобразований «из lvalue в rvalue», «из массива в указатель» и «из функции в указатель» каждый аргумент из списка аргументов переменной длины подвергается дополнительным преобразованиям, известным как продвижения аргументов по умолчанию:
| (начиная с C++11) |
- Аргументы типа float преобразуются в double, как при продвижении чисел с плавающей точкой.
- bool, char, short и неограниченные перечисления преобразуются в int или целочисленные типы большей разрядности, как при целочисленном продвижении.
Типы классов, не являющиеся POD(до C++11)Перечисления с областью видимости и типы классов с доступным нетривиальным конструктором копирования, доступным нетривиальным конструктором перемещения или нетривиальным деструктором(начиная с C++11) условно поддерживаются при потенциально вычисляемых вызовах с семантикой, определяемой реализацией (эти типы всегда поддерживаются в невычисляемых вызовах).
Поскольку параметры с переменным числом аргументов имеют самый низкий ранг при разрешении перегрузки, их часто используют в качестве универсальных запасных вариантов в SFINAE.
В теле функции, использующей аргументы переменного числа, значения этих аргументов можно получить с помощью средств библиотеки <cstdarg>:
Определено в заголовке <cstdarg> |
|
|---|---|
| предоставляет доступ к аргументам функции с переменным числом аргументов (макрос-функция) |
|
| получает следующий аргумент функции с переменным числом аргументов (макрос-функция) |
|
|
(C++11) | создаёт копию аргументов функции с переменным числом аргументов (макрос-функция) |
| завершает перебор аргументов функции с переменным числом аргументов (макрос-функция) |
|
хранит сведения, необходимые для va_start, va_arg, va_end и va_copy (определение типа) |
|
Поведение макроса va_start не определено, если последний параметр перед многоточием имеет ссылочный тип или тип, который не совместим с типом, получаемым в результате продвижений аргументов по умолчанию.
| Если раскрытие пакета или сущность, полученная в результате захвата лямбда-выражением, используется в качестве последнего параметра в | (начиная с C++11) |
Альтернативы
| (начиная с C++11) |
Примечания
В языке программирования C до C23 перед параметром-многоточием должен присутствовать хотя бы один именованный параметр, поэтому R printz(...); допустима только начиная с C23. В C++ эта форма разрешена, хотя аргументы, переданные такой функции, недоступны; её часто используют как запасную перегрузку в SFINAE, используя самый низкий приоритет преобразования многоточия при разрешении перегрузки.
Этот синтаксис для аргументов переменного числа был введён в C++ в 1983 году без запятой перед многоточием. Когда в C89 были заимствованы прототипы функций из C++, синтаксис заменили на вариант, требующий запятую. Для совместимости в C++98 принимаются оба варианта: f(int n...) в стиле C++ и f(int n, ...) в стиле C. Исходная грамматика в стиле C++ считается устаревшей начиная с C++26.
| В сокращённых шаблонах функций можно использовать запятую, чтобы многоточие обозначало функцию с переменным числом аргументов, а не шаблон с переменным числом параметров:
| (начиная с C++20) |
Отчёты об исправлениях
Следующие отчёты об исправлениях, изменяющих поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применён к | Опубликованное поведение | Правильное поведение |
|---|---|---|---|
| CWG 506 | C++98 | передача аргументов классов, не являющихся POD, через многоточие приводила к неопределённому поведению | передача таких аргументов условно поддерживается с семантикой, определяемой реализацией |
| CWG 634 | C++98 | условная поддержка типов классов мешала работе некоторых идиом SFINAE | всегда поддерживаются в невычисляемом контексте |
| CWG 2247 | C++11 | не было ограничений на передачу пакета параметров или захвата лямбда-выражения в va_start | сделано некорректным, диагностика не требуется |
| CWG 2347 | C++11 | было неясно, подвергаются ли перечисления с областью видимости, переданные через многоточие, продвижениям аргументов по умолчанию | передача перечислений с областью видимости условно поддерживается с семантикой, определяемой реализацией |
См. также
| Документация по C о аргументах переменного числа | |
| Документация по Cнеявных преобразованиях |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/variadic_arguments