这个变量参数表示法如何工作?

时间:2014-01-03 21:39:03

标签: c++ arguments variadic-functions

在C ++中,我可以定义一个具有可变数量参数的函数,如下所示:

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

并称之为:

a(100, 200, 300);

但是,显然我只能访问第一个参数:调用的输出是100

如何使用此表示法访问其他参数?

5 个答案:

答案 0 :(得分:4)

你的语法是......不幸的,并且是指C风格的vararg函数。

在C ++ 11中,你应该更喜欢variardic template。最简单的方法是这样的:

首先,一些帮助代码:

#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 :(得分:1)

如果使用var args接口,则需要能够从命名参数中分辨出总共提供了多少个参数。例如,<stdio.h>函数通过将格式字符串作为最后一个命名参数,然后使用参数列表中指定的参数来执行此操作。要访问参数,您需要使用各种va_...函数和类型。

使用可变参数模板会好得多:

template <typename... T>
void f(T... a) {
    // just expand the parameter pack over here
}

答案 2 :(得分: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)解析为整数,然后我们将其丢弃为数组;这让我们可以在复杂语句中使用包扩展运算符。

答案 3 :(得分: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;
}

答案 4 :(得分: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的格式参数。
  4. 在这个例子中,我简单地假设有三个参数。使用更多或更少的参数调用a将导致未定义的行为(读取,随机结果,崩溃)。