Calling a variadic function with an unknown number of parameters

蹲街弑〆低调 提交于 2019-12-01 06:40:34

问题


Say I have a function that takes a variable number of parameters: I want to call this function from somewhere else, building the list of parameters, but without knowing in advance how many parameters I'll need.

Sorry that's not well explained, hopefully this code makes my question clearer:

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

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

That function's being called from this one:

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.
  //

}

回答1:


Actually building a variable-length argument list at run-time -- which is what I'm pretty sure you're trying to do -- is pretty tricky. There's no way to do it at all in Standard C, but there are various tricks you can try.

Perhaps the best is the "Foreign Function Interface Library" at http://sourceware.org/libffi/ .

See also question 15.13 in the C FAQ list: http://c-faq.com/varargs/invvarargs.html


See also these previous Stackoverflow questions:
C late binding with unknown arguments
How to call functions by their pointers passing multiple arguments in C?




回答2:


You will need a terminating parameter, it may be NULL, or something else, that should never appear in your real arguments. Inside your function you can loop over the arguments until you reach a terminating NULL or any other value you choose to signal the end.




回答3:


If a special value cannot be reserved to indicate the end of the list, pass 2 arguments for each parameter. Tad wasteful but does allow code to be sequentially automatically generated without value restrictions.

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



回答4:


The easier way to do at runtime what the OP asked is probably by relying on standard containers like std::vectors and the others.

Anyway, for the sake of completeness, here is an example of how a variadic pack of parameters can be created at compile time and used later to invoke a function:

#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>{});
}

Unfortunately, for it must be completely resolved at compile time, the argument for the bar function cannot be a std::size_t for itself.
Instead, a std::integral_constant can be used to do that.




回答5:


When I've need to do something like this, I got it to work with a "switch-fan".

switch( n ){
case 1:  foo(0);     break;
case 2:  foo(0,0);   break;
case 3:  foo(0,0,0); break;
}


来源:https://stackoverflow.com/questions/35093317/calling-a-variadic-function-with-an-unknown-number-of-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!