不定長度引數


如果函式想要能接受不定長度的引數(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); 
}