Переменное число аргументов
Позволяет функции принимать любое количество дополнительных аргументов.
Обозначается конечным ... (кроме вводящего расширение пакета) (начиная с 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) |
- аргументы 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 не определено, если последний параметр перед многоточием имеет ссылочный тип или имеет тип, несовместимый с типом, полученным в результате продвижения аргумента по умолчанию.
Если расширение пакета или сущность, полученная в результате лямбда-захвата, используется в качестве последнего параметра в va_start, программа некорректна, диагностика не требуется. |
(начиная с C++11) |
[править] Альтернативы
|
(начиная с 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...) |
(начиная с C++20) |
[править] Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
Номер | Применён | Поведение в стандарте | Корректное поведение |
---|---|---|---|
CWG 506 | C++98 | передача аргументов класса, отличного от POD, в многоточие приводила к неопределённому поведению |
передача таких аргументов поддерживается условно с семантикой, определяемой реализацией |
CWG 634 | C++98 | условно-поддерживаемые типы классов сделали некоторые идиомы SFINAE неработоспособными |
всегда поддерживается, если не оценивается |
CWG 2247 | C++11 | нет ограничений на передачу пакета параметров или лямбда-захвата в va_start
|
сделано неправильным, диагностика не требуется |
CWG 2347 | C++11 | было неясно, подлежат ли перечисления с областью видимости, переданные многоточию, продвижению аргументов по умолчанию |
передача перечислений с областью видимости поддерживается условно с семантикой, определяемой реализацией |
[править] Смотрите также
Документация C по Переменное число аргументов
|