В C++ можно создавать функции с произвольным количеством аргументов в стиле C, используя заголовок <cstdarg>, который предоставляет инструменты для работы с переменным числом аргументов. Эти функции иногда называют variadic functions.
Основные элементы
Для работы с такими функциями используются три макроса:
- va_list: Тип, предназначенный для хранения информации, необходимой для работы с аргументами.
- va_start: Инициализирует- va_listдля доступа к аргументам.
- va_arg: Извлекает следующий аргумент из списка.
- va_end: Завершает работу с- va_list.
Пример использования
Рассмотрим функцию, которая суммирует произвольное количество целых чисел.
Пример кода
#include <iostream>
#include <cstdarg>
 
int sum(int count, ...) {
    int total = 0;
 
    va_list args;
    va_start(args, count);
 
    for (int i = 0; i < count; ++i) {
        total += va_arg(args, int);
    }
 
    va_end(args);
    return total;
}
 
int main() {
    std::cout << "Sum of 1, 2, 3: " << sum(3, 1, 2, 3) << std::endl;
    std::cout << "Sum of 4, 5, 6, 7: " << sum(4, 4, 5, 6, 7) << std::endl;
    return 0;
}Пояснение
- Функция sum:- Принимает первый параметр count, который указывает количество последующих аргументов.
- Использует макрос va_listдля хранения состояния аргументов.
- va_start(args, count)инициализирует- va_list argsдля доступа к аргументам, начиная с- count.
- В цикле va_arg(args, int)извлекает каждый последующий аргумент типаint.
- va_end(args)завершает работу с- va_list.
 
- Принимает первый параметр 
Ограничения и риски
- Отсутствие проверки типов: Компилятор не может проверить типы передаваемых аргументов, что может привести к ошибкам во время выполнения.
- Требование явно указывать количество аргументов: Для работы функции нужно передавать количество аргументов.
- Отсутствие информации о типах: Функция должна знать тип каждого аргумента заранее.
Реализация с разными типами данных
Если нужно работать с разными типами данных, обычно добавляют дополнительный параметр, указывающий типы аргументов. Это может быть сделано с помощью строкового формата.
Пример кода
#include <iostream>
#include <cstdarg>
#include <string>
 
void printFormatted(const char* format, ...) {
    va_list args;
    va_start(args, format);
 
    while (*format != '\0') {
        if (*format == 'd') {
            int i = va_arg(args, int);
            std::cout << i << " ";
        } else if (*format == 'c') {
            char c = va_arg(args, int);  // char is promoted to int
            std::cout << c << " ";
        } else if (*format == 'f') {
            double d = va_arg(args, double);
            std::cout << d << " ";
        }
        ++format;
    }
 
    va_end(args);
    std::cout << std::endl;
}
 
int main() {
    printFormatted("dcf", 42, 'A', 3.14);
    printFormatted("cdd", 'B', 123, 456);
    return 0;
}Пояснение
- Функция printFormatted:- Принимает строку формата format, указывающую типы последующих аргументов.
- Использует макросы va_list,va_start,va_arg, иva_endдля обработки аргументов.
- В цикле проверяет каждый символ строки формата и в зависимости от него извлекает соответствующий аргумент.
 
- Принимает строку формата 
Заключение
Функции с произвольным количеством аргументов в стиле C обеспечивают гибкость и удобство, но требуют осторожного использования из-за отсутствия проверки типов на этапе компиляции. Для более безопасного и типизированного подхода можно рассмотреть использование таких возможностей C++ как шаблоны и стандартные библиотеки, такие как std::initializer_list.