Spec-Zone.ru › C++

Аргументы переменной длины

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

Указывается заключительным ... (кроме введения расширения пакета)(с 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

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

(с C++11)

Неявные преобразования по умолчанию

При вызове функции с переменным числом аргументов, после преобразований «lvalue-to-rvalue», «array-to-pointer» и «function-to-pointer» преобразований, каждый аргумент, являющийся частью списка аргументов переменной длины, подвергается дополнительным преобразованиям, известным как преобразования по умолчанию:

  • std::nullptr_t преобразуется в void*
(с C++11)
  • Аргументы float преобразуются в double аналогично преобразованиям с плавающей точкой
  • bool, char, short, и неименованные перечисления преобразуются в int или более широкие целочисленные типы, аналогично преобразованиям целых чисел

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

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

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

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

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

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

(с 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, ...).

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

void f1(auto...); // same as template<class... Ts> void f3(Ts...)void f2(auto, ...); // same as template<class T> void f3(T...)

(с 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API