Tash1moto
@Tash1moto

Как на C++ узнать количество передаваемых аргументов?

После python, js, для интереса смотрю C++
Как можно на C++ узнать количество аргументов?

К примеру на питоне3 можно сделать так
f = lambda *args: print(len(args))
f(1,2,3) # выведет 3

Смотрел вариант с библиотекой cstdarg, но это какой то велосипед мне кажется и явно надо указывать первым аргументом количество аргументов :).
Так как же узнать количество передаваемых аргументов на C++ ?
  • Вопрос задан
  • 2451 просмотр
Решения вопроса 2
MrNexeon
@MrNexeon
Быстро и легко. Считаем с помощью вариативных шаблонов и оператора sizeof

template <typename ... Args> int ArgsCount(Args ... args) {
    return sizeof...(args);
}

std::cout << ArgsCount(1, "hello", 2.f); // Вывод: 3
Ответ написан
Комментировать
@Mercury13
Программист на «си с крестами» и не только
Какие есть способы физически, на уровне машинного кода, передать переменное число параметров в подпрограмму?

1. Автобоксинг в массив. Если к тому же тип элементов может быть любым — тогда будет массив «лёгких» или обычных variant’ов, или массив объектов на «куче». В Delphi для этого используется лёгкий variant (см. SysUtils.Format), в Java и других «мусорных» языках — объекты на куче. В Си++ нет.

2. Автоматически развернуть такой вызов в кучу вызовов поменьше. См. вариативные шаблоны C++11 = variadic templates. В Си++ есть, штука тяжёлая, я с ней и сам знаком поверхностно и ничего толком рассказать не могу. Но вот кое-что набросал.
#include <iostream>

constexpr int countArgs() { return 0; }

template <class Arg, class ... Args>
constexpr int countArgs(const Arg& x, const Args& ... args)
{
    return countArgs(args...) + 1;
}

int main()
{
    std::cout << countArgs() << std::endl;
    std::cout << countArgs(1, 2, 3) << std::endl;
    return 0;
}

Может быть, и первый путь удастся завернуть в массив через вариативные шаблоны, но я не в курсе. А вот обрабатывать аргументы по одному — за милую душу!

3. Использовать особые соглашения вызова и раскручивать стек, пока не попадётся какой-то маркер «больше параметров нет» (см. работу с формами cURL), или окольным путём узнать количество параметров (см. printf). Есть даже в Си (который не что иное, как «ассемблер высокого уровня»), штука очень системная и чреватая ошибками.

4. Возможна ещё и такая фишка: физически оно устроено как printf, но обёрнуто в «лёгкий» вариативный шаблон, который защищает всё это добро от ошибок программиста.
#include <iostream>
#include <cstdarg>

constexpr int countArgs() { return 0; }

template <class ... Args>
constexpr int countArgs(int x, Args ... args)
{
    return countArgs(args...) + 1;
}

void outArgsInner(int count, ...)
{
    va_list ap;
    va_start(ap, count);
    if (count > 0) {
        std::cout << va_arg(ap, int);
        for (int i = 2; i <= count; ++i) {
            std::cout << ' ' << va_arg(ap, int);
        }
    }
    va_end(ap);
    std::cout << std::endl;
}


template <class ... Args>
inline void outArgs(Args ... args)
{
    outArgsInner(countArgs(args...), args...);
}

int main()
{
    outArgs();      // пустой тоже работает
    outArgs(1, 2, 3);
    // outArgs("a", 2, 3);   тут ошибка! — и верно, мы принимаем только int’ы
    return 0;
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
15432
@15432
Системный программист ^_^
Функции на c++ по большей части имеют фиксированное число параметров, так что с определением числа параметров нет проблем - это известно на этапе компиляции.
Функции с переменным числом параметров (например, printf(char* format, ...) )имеют свой механизм определения числа параметров, который вы сами должны закодить на ваше усмотрение. Можете первым аргументом подавать общее число аргументов, как и предлагаете.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы