Аргументы переменной длины
Позволяет функции принимать любое количество дополнительных аргументов.
Указывается заключительным ... (кроме введения расширения пакета)(с C++11) после списка параметров объявления функции.
Когда список параметров не пустой, перед ... может стоять необязательная запятая, что указывает на функцию с переменным числом аргументов. Это обеспечивает совместимость с C (который добавил требование о запятой, когда он принял прототипы функций из C++).
// the function declared as follows
int printx(const char* fmt...);
// may be called with one or more arguments:
printx("hello world");
printx("a=%d b=%d", a, b);
int printx(const char* fmt, ...); // same as above (extraneous comma is allowed
// for C compatibility)
int printy(..., const char* fmt); // error: ... cannot appear as a parameter
int printz(...); // valid, but the arguments cannot be accessed portably|
Примечание: это отличается от расширения пакета параметров функции, которое указывается многоточием, являющимся частью декларатора параметра, а не многоточием, которое появляется после всех объявлений параметров. Как расширение пакета параметров, так и многоточие «переменной длины» могут появляться в объявлении шаблона функции, как в случае |
(с C++11) |
Неявные преобразования по умолчанию
При вызове функции с переменным числом аргументов, после преобразований «lvalue-to-rvalue», «array-to-pointer» и «function-to-pointer» преобразований, каждый аргумент, являющийся частью списка аргументов переменной длины, подвергается дополнительным преобразованиям, известным как преобразования по умолчанию:
|
(с 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 (typedef) |
|
Поведение макроса va_start неопределено, если последний параметр перед многоточием имеет тип ссылки или тип, несовместимый с типом, полученным в результате преобразований по умолчанию.
|
Если расширение пакета параметров или сущность, полученная в результате захвата лямбды, используется в качестве последнего параметра в |
(с C++11) |
Альтернативы
|
(с C++11) |
Примечания
В языке C до C23 перед многоточием должен быть хотя бы один именованный параметр, поэтому R printz(...); недопустим до C23. В C++, эта форма разрешена, даже если аргументы, переданные в такую функцию, недоступны, и часто используется в качестве запасного варианта перегрузки в SFINAE, используя наименьший приоритет преобразования многоточия в разрешении перегрузки.
Этот синтаксис для аргументов переменной длины был представлен в C++ 1983 без запятой перед многоточием. Когда C89 принял прототипы функций из C++, он заменил синтаксис на синтаксис, требующий запятой. Для совместимости C++98 принимает как синтаксис C++-стиля f(int n...), так и синтаксис C-стиля f(int n, ...).
|
Запятая может использоваться в сокращенных шаблонах функций, чтобы многоточие указывало на функцию с переменным числом аргументов вместо шаблона функции с переменным числом аргументов:
|
(с 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 по Аргументам переменной длины |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/variadic_arguments