Как работает эта переменная запись аргумента?

0

В C++ я могу определить функцию с переменным числом таких аргументов:

void a(int a...) {
    std::cout << a << std::endl;
}

И назовите это так:

a(100, 200, 300);

Однако, по-видимому, я могу получить доступ только к первому аргументу: вывод вызова равен 100.

Как получить доступ к другим аргументам с помощью этих обозначений?

  • 5
    man va_list для начальной точки. Но если вы хотите сделать что-то подобное в C ++ 11, забудьте об этом и variadic templates числом variadic templates .
  • 0
    Вы знакомы с функциями va_list или variadic в C или C ++? Возможно, вы захотите найти va_list .
Показать ещё 9 комментариев
Теги:
arguments
variadic-functions

5 ответов

0
Лучший ответ

Пример кода с использованием вашей функции a:

#include <iostream>
#include <cstdarg>

void a(int a...)
{
    va_list args;
    va_start(args, a);
    int b = va_arg(args, int);
    int c = va_arg(args, int);

    std::cout << a << ", " << b << ", " << c << std::endl;
}

int main()
{
    a(100, 200, 300);
    return 0;
}

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

  1. Первым параметром является количество параметров.
  2. Последний параметр - разделитель, NULL или другое уникальное значение, например.
  3. Первый параметр имеет другую встроенную информацию, которая определяет количество, порядок и тип параметров, например параметр формата для printf.

В этом примере я просто предположил, что существует три параметра. Вызов с более или менее параметров приведет к неопределенному поведению (чтение, случайные результаты, к аварии). a

4

Ваш синтаксис... неудачный и относится к функции vararg в стиле C.

В С++ 11 вам следует выбрать template s. Самый простой подход - это примерно так:

Во-первых, некоторый код помощника:

#include <utility>
template<typename Lambda>
void for_each_arg( Lambda&& unused ) {}

template<typename Lambda, typename Arg1, typename... Args>
void for_each_arg( Lambda&& closure, Arg1&& arg1, Args&&... args ) {
  closure( std::forward<Arg1>(arg1) );
  for_each_arg( std::forward<Lambda>(closure), std::forward<Args>(args)... );
}

теперь мы используем его:

#include <iostream>
template<typename... Args>
void foo( Args&&... args ) {
  for_each_arg( [](int x){
    std::cout << x << "\n";
  }, std::forward<Args>(args)... );
}
int main() {
  foo( 1, 2, 3 );
}

и мы можем получить доступ к каждому аргументу и убедиться, что они преобразуются в int. Обратите внимание, что преобразование в int отложено до вызова тела for_each_arg.

1

Если вы используете интерфейс var args, вам нужно указать из названных параметров, сколько аргументов содержится в общей сложности. Например, функция <stdio.h> делает это, если строка формата является последним именованным аргументом, за которой следует столько аргументов, как указано в списке аргументов. Чтобы получить доступ к аргументам, вам нужно использовать различные функции и типы va_...

Вам гораздо лучше использовать вариативные шаблоны:

template <typename... T>
void f(T... a) {
    // just expand the parameter pack over here
}
  • 1
    этот ответ будет очень полезен, если вы захотите уточнить, как вы «расширяете пакет параметров»
  • 2
    @Bathsheba: в простейшем случае вы бы использовали g(a...) но одно это не очень помогает, и описание того, как полностью это сделать, довольно сложно! Вероятно, самый простой подход - это использовать auto t(std::tie(a...)); а затем получить доступ к t с помощью std::get<...>(t) .
Показать ещё 1 комментарий
0

Решение, которое обеспечивает тип int.
Но с использованием немного отличается

#include <initializer_list>
#include <iostream>

// Or you may use std::vector
void print(const std::initializer_list<int>& a) {
    for (auto elem : a) {
        std::cout << elem << std::endl;
    }
}

int main(int argc, char *argv[])
{
    print({1, 2, 3}); // extra braces.
    return 0;
}
0

Другое вариационное решение:

template<typename T, typename... Vs>
void print(T&& t, Vs&&... vs) {
  std::cout << std::forward<T>(t) << std::endl;
  int sink[] { (std::cout << " " << std::forward<Vs>(vs) << std::endl, 0)... };
  (void)sink; // silence "unused variable" warning                                        
}

Который имеет преимущество не требовать помощников. Мы используем расширение пакета для пересылки каждого аргумента по одному в cout. По причинам синтаксиса я использую оператор запятой, чтобы выражение (cout..stuff.., 0) разрешало целое число, которое мы затем отбрасываем в массив; это позволяет нам использовать оператор расширения пакета вокруг нашего сложного оператора.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню