2016-01-29 3 views
3

Скажем, у меня есть функция, которая принимает переменное количество параметров: я хочу вызвать эту функцию из другого места, создав список параметров, но не зная заранее, сколько параметров Мне нужно.Вызов переменной функции с неизвестным количеством параметров

Жаль, что не очень хорошо объяснил, надеюсь, этот код делает мой вопрос яснее:

void foo(int n, ...) { 
    va_list vl; 
    va_start(vl,n); 

    for (int i = 0; i<n; i++) { 
     // Do something to each passed variable 
    } 
} 

Эта функция бытии вызывается из этого один:

void bar(int howManyParams) { 

    // Here I want to call foo() with howManyParams parameters 
    // (values are irrelevant for the question) 
    // 
    // I.e. for howManyParams = 1, we should call foo(0) 
    //  for howManyParams = 2, we should call foo(0,0) 
    //  for howManyParams = 3, we should call foo(0,0,0) 
    // etc. 
    // 

} 
+3

Использование массива здесь было бы намного более подходящим ... –

+0

Как правило, для вызывающего есть какое-то соглашение, чтобы обозначить, сколько переменных функция должна выходить из стека. Например, printf() и его варианты имеют строку формата, где есть определенные маркеры формата, соответствующие переданным аргументам. Или иногда, соглашение состоит в том, что определенное значение, такое как ноль, будет означать конец аргументов. Вам решать эту конвенцию. –

+1

Хотя, поскольку ваш вопрос отмечен C++, вы можете рассмотреть возможность передачи контейнера с известным размером, такого как std :: vector, вместо того, чтобы полагаться на переменные аргументы. –

ответ

3

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

Возможно, лучшим является «Библиотека интерфейса внешних функций» по адресу http://sourceware.org/libffi/.

Смотрите также вопрос 15.13 в списке C Справка: http://c-faq.com/varargs/invvarargs.html


Смотрите так же эти предыдущие вопросы StackOverflow:
C late binding with unknown arguments
How to call functions by their pointers passing multiple arguments in C?

+0

Если это то, что хочет OP (я подозреваю, что вы правы), это становится кошмаром отладки. – Olaf

+0

Да, это то, о чем я просил. Спасибо за советы, у меня будет пересмотр, чтобы избежать этого. – CharlieB

2

Вам нужен параметр завершающего, это может быть NULL или что-то еще, что никогда не должно появляться в ваших реальных аргументах. Внутри вашей функции вы можете перебрать аргументы до тех пор, пока не достигнете завершающего NULL или любого другого значения, которое вы решите сигнализировать о завершении.

+0

См. Функцию 'execl' для примера этого малыша функции. – dbush

+2

Как это помогает реализовать «бар»? –

+0

Похоже, что 'n' предназначен для этого. – Olaf

0

Если специальное значение не может быть зарезервировано для указания конца списка, передайте 2 аргумента для каждого параметра. Tad расточительный, но позволяет автоматически генерировать код без ограничений стоимости.

foo(0); 
foo(1, Params1, 0); 
foo(1, Params1, 1, Params2, 0); 
foo(1, Params1, 1, Params2, 1, Params3, 0); 
0

Чем проще способ сделать во время выполнения, что ОП просили вероятно, полагаясь на стандартные контейнеры, такие как std::vector и другие.

Во всяком случае, для полноты картины, вот пример того, как VARIADIC пакет параметров может быть создан во время компиляции и использоваться в дальнейшем для вызова функции:

#include<utility> 
#include<tuple> 
#include<iostream> 

auto params(std::index_sequence<0>) { 
    return std::tuple<std::size_t>{}; 
} 

template<std::size_t I, std::size_t... O> 
auto params(std::index_sequence<I, O...>) { 
    auto tup = std::tuple<std::size_t>{ sizeof...(O) }; 
    auto seq = std::make_index_sequence<sizeof...(O)>{}; 
    return std::tuple_cat(tup, params(seq)); 
} 

void foo() { 
    std::cout << "done." << std::endl; 
} 

template<typename Arg, typename... Args> 
void foo(Arg &&arg, Args&&... args) { 
    std::cout << "arg: " << arg << ", still to be elaborated: " << sizeof...(Args) << std::endl; 
    foo(std::forward<Args>(args)...); 
} 

template<typename... Args, std::size_t... Indexes> 
void invoke(std::tuple<Args...> &tup, std::index_sequence<Indexes...>) { 
    foo(std::get<Indexes>(tup)...); 
} 

template<std::size_t N> 
void bar(std::integral_constant<std::size_t, N> size) { 
    auto seq = std::make_index_sequence<N>{}; 
    auto tup = params(seq); 
    invoke(tup, seq); 
} 

int main() { 
    bar(std::integral_constant<std::size_t, 3>{}); 
    bar(std::integral_constant<std::size_t, 5>{}); 
} 

К сожалению, для этого должно быть полностью разрешен во время компиляции, аргумент функции bar не может быть std::size_t для себя.
Вместо этого для этого можно использовать std::integral_constant.

Смежные вопросы