Spec-Zone.ru › C++

Аргументы переменного числа

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

Функция является функцией с переменным числом аргументов, если последний параметр её списка параметров — многоточие (...).

Запятую перед многоточием можно опустить. (устарело в 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

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

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

Продвижения аргументов по умолчанию

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

  • 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
(определение типа)

Поведение макроса 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 принимаются оба варианта: f(int n...) в стиле C++ и f(int n, ...) в стиле C. Исходная грамматика в стиле C++ считается устаревшей начиная с C++26.

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

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 о аргументах переменного числа
Документация по Cнеявных преобразованиях

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/variadic_arguments

Spec-Zone.ru

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