В C++ я могу определить функцию с переменным числом таких аргументов:
void a(int a...) {
std::cout << a << std::endl;
}
И назовите это так:
a(100, 200, 300);
Однако, по-видимому, я могу получить доступ только к первому аргументу: вывод вызова равен 100
.
Как получить доступ к другим аргументам с помощью этих обозначений?
Пример кода с использованием вашей функции 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;
}
Синтаксис переменных аргументов не знает числа или типа параметров. Поэтому в списке параметров должно указываться количество и, возможно, тип параметров. Существует несколько методов, которые обычно используются для определения количества параметров:
В этом примере я просто предположил, что существует три параметра. Вызов с более или менее параметров приведет к неопределенному поведению (чтение, случайные результаты, к аварии). a
Ваш синтаксис... неудачный и относится к функции 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
.
Если вы используете интерфейс var args, вам нужно указать из названных параметров, сколько аргументов содержится в общей сложности. Например, функция <stdio.h>
делает это, если строка формата является последним именованным аргументом, за которой следует столько аргументов, как указано в списке аргументов. Чтобы получить доступ к аргументам, вам нужно использовать различные функции и типы va_...
Вам гораздо лучше использовать вариативные шаблоны:
template <typename... T>
void f(T... a) {
// just expand the parameter pack over here
}
g(a...)
но одно это не очень помогает, и описание того, как полностью это сделать, довольно сложно! Вероятно, самый простой подход - это использовать auto t(std::tie(a...));
а затем получить доступ к t
с помощью std::get<...>(t)
.
Решение, которое обеспечивает тип 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;
}
Другое вариационное решение:
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) разрешало целое число, которое мы затем отбрасываем в массив; это позволяет нам использовать оператор расширения пакета вокруг нашего сложного оператора.
va_list
для начальной точки. Но если вы хотите сделать что-то подобное в C ++ 11, забудьте об этом иvariadic templates
числомvariadic templates
.va_list
или variadic в C или C ++? Возможно, вы захотите найтиva_list
.