繁体   English   中英

使用未知数量的参数调用可变参数函数

[英]Calling a variadic function with an unknown number of parameters

假设我有一个带有可变数量参数的函数:我想从其他地方调用这个函数,构建参数列表,但事先不知道我需要多少个参数。

对不起,没有得到很好的解释,希望这段代码能让我的问题更加清晰:

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

}

实际上在运行时构建一个可变长度的参数列表 - 这是我非常肯定你要做的 - 非常棘手。 在标准C中根本无法做到这一点,但你可以尝试各种技巧。

也许最好的是http://sourceware.org/libffi/上的“外部函数接口库”。

另见C FAQ列表中的问题15.13: http//c-faq.com/varargs/invvarargs.html


另请参阅以前的Stackoverflow问题:
C后期绑定与未知参数
如何通过指针在C中传递多个参数来调用函数?

您将需要一个终止参数,它可能是NULL或其他东西,它们永远不会出现在您的真实参数中。 在函数内部,您可以遍历参数,直到达到终止NULL或您选择用于表示结束的任何其他值。

如果无法保留特殊值以指示列表的结尾,则为每个参数传递2个参数。 有点浪费,但允许在没有价值限制的情况下顺序自动生成代码。

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

在运行时更简单的方法是OP可能依赖标准容器,如std::vector s和其他容器。

无论如何,为了完整起见,这里是一个如何在编译时创建可变参数包并稍后用于调用函数的示例:

#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来做到这一点。

当我需要做这样的事情时,我让它与“开关风扇”一起工作。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM