Как можно использовать функцию variadi c без передачи количества аргументов и только с 3 точками? - PullRequest
0 голосов
/ 19 февраля 2020

Учитывая приведенный ниже код, возможно ли определить функцию variadi c без получения количества аргументов?

void printFunction(...)
{
    int noOfArgs = "Any way to get number of arguments?";
    va_list args;
    va_start(args, noOfArgs);
    cout << va_arg(args, int) << endl;
    for (int i = 2; i <= noOfArgs; i++)
    {
        cout << va_arg(args, int) << endl;
    }
    va_end(args);
}


int main()
{

    printFunction(1, 2, 3, 4, 5);

    return 0;
}

Ответы [ 3 ]

2 голосов
/ 19 февраля 2020

В C ++ 11 и более поздних версиях это очень просто:

template<typename... Arguments>
void printFunction(Arguments &&...args) {
    auto noOfArgs = sizeof...(Arguments);

Тем не менее, вы используете старый стиль, простой - C, стиль макроса препроцессора, который сильно отличается. Во-первых, чтобы использовать макросы препроцессора, у вас должен быть хотя бы один именованный параметр, который будет использоваться для запуска va_list, и это начало осложнений.

Я думаю, что не существует стандартного способа посчитать количество аргументов, это может быть реализовано несколькими способами, если это то, что вы действительно спрашиваете, который я бы пометил как C вместо C++.

Как получить доступ к аргументы: есть два варианта, назовем его «пулемет» и «капельно-капельно-капельно» - это мои имена -:

#include <utility>

template<typename... Ts>
void ignoreResults(Ts &&...) {}

template<typename Argument>
int machineGunBullet(Argument &&arg);

inline void drip() {} // do nothing

template<typename A1, typename... Tail>
void drip(A1 &&a1, Tail &&...tail) {
    // do something here with a1
    drip(std::forward<Tail>(tail)...);
}

template<typename... Arguments>
void printFunction(Arguments &&...args) {
    ignoreResults(machineGunBullet(std::forward<Arguments>(args))...);
    // or
    drip(std::forward<Arguments>(args)...);
}

Это сборка в проводнике компилятора, https://godbolt.org/z/aSx2wv

2 голосов
/ 19 февраля 2020

Получение количества аргументов невозможно в C va_args. Лучшее, что вы можете сделать, это использовать значение magi c, которое завершает последовательность, и макрос, чтобы скрыть ее от вашего пользователя:

#define printFunction(...) actualPrintFunction(__VA_ARGS__, 42)
void actualPrintFunction(int first, ...)
{
    va_list args;
    va_start(args, first);
    int arg;
    std::cout << first << endl;
    while((arg = va_arg(args, int)) != 42)
    {
        cout << arg << endl;
    }
    va_end(args);
}

Как уже упоминалось в комментариях, вы могли бы альтернативно использовать выражения свёртывания C ++ , Преимущество вышеописанного заключается в том, что он совместим с C и быстрее компилируется, а подход C ++ обеспечивает безопасность типов .

1 голос
/ 19 февраля 2020

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

Однако обратите внимание, что чтобы использовать va_start, должен быть хотя бы один именованный параметр. В вашем примере вы пытаетесь передать локальную переменную в va_start, что недопустимо. Этот макрос не принимает «количество аргументов». Он принимает «последний именованный аргумент до запуска variadi c параметров».

При этом: я рекомендую не использовать C -типы variadi c.

...