不定长度实参


如果函数想要能接受不定长度的实参(Variable-length argument),基本上可以使用vector定义参数,而调用方使用vector收集实参后,再来调用函数,例如:

#include <iostream>
#include <vector> 
using namespace std; 

void foo(vector<double>); 

int main() { 
    vector<double> args;

    args.push_back(1.1);
    args.push_back(2.2);
    args.push_back(3.3);

    foo(args);

    return 0; 
} 

void foo(vector<double> args) { 
    for(auto arg : args) {
       cout << arg << endl; 
    } 
}

现代程序语言,不少都提供了定义不定长度实参的特定语法,令调用函数时可以更自然,像是foo(1.1, 2.2, 3.3),就这点而言,C++ 11 可以有两个方案,一是定义参数类型为initializer_list,透过清单初始化化(list initialization)令调用函数的语法更方便一些;另一个方式是透过可变参数模版(variadic template)来定义,这需要认识模版语法等更多细节,之后再来谈。

initializer_list定义于initializer_list标头文件,来看看如何使用:

#include <iostream>
#include <initializer_list> 
using namespace std; 

void foo(initializer_list<double>); 

int main() { 
    foo({1.1, 2.2, 3.3});

    return 0; 
} 

void foo(initializer_list<double> args) { 
    for(auto arg : args) {
       cout << arg << endl; 
    } 
}

在调用函数时,使用了清单初始化化{}包含了实参,实际上,如果foo定义参数时使用vector,这个范例也可以运作,那为何要改为initializer_list?因为清单初始化化{}会创建initializer_list,而vector不过就是有个构造函数,可以接受initializer_list,才令vector也可以使用清单初始化化。

简单来说,只是想定义不定长度实参时,initializer_list就可以了,不过它包含的方法比较少,如果需要vector的方法,使用vector当然也是可以。

C++ 中也可以使用C 风格的不定长度实参,然而并不建议,若要与具有 C 风格的不定长度实参互动,可以包含cstdarg标头文件,底下是个范例:

#include <iostream> 
#include <cstdarg> 
using namespace std; 

void foo(int, ...); 

int main() { 
    foo(3, 1.1, 2.2, 3.3);

    return 0; 
} 

void foo(int size, ...) { 
    va_list args; 
    va_start(args, size); 

    for(int i = 0; i < size; i++) {
        cout << va_arg(args, double) << endl; 
    }

    va_end(args); 
}




展开阅读全文