可變參數模板
語法
Args代表多個不同類型與數量的參數。
以下三種…位置不同,都可以。
template<typename... Args>
template<typename ...Args>
template<typename ... Args>
參數清單
以下程式碼”Bill”,”Mary”,”Tom”,”Allen”就是參數清單。
1
2
3
4
int main() {
print("Bill","Mary","Tom","Allen");
return 0;
}
遞迴呼叫
以下的模板是遞迴的方式在運作
- T為類型
- …Args為參數清單類型
- arg為每一次遞迴,就會從參數清單取出一個
- args為每一次遞迴,未被取出的剩下參數清單
1
2
3
4
5
6
7
template<typename T, typename... Args>
void print(T arg, Args... args) {
//每呼叫一次就從args中拿出一個參數arg
cout << "參數" << arg << endl;
//剩下未取出的參數繼續遞迴呼叫自已
print(args...);
}
遞迴結束呼叫的函式
- 參數為空(因為可變參數清單已經全取出來,也沒參數可傳遞)
- 傳回值型態void
1
2
3
void print() {
cout << "end" << endl;
}
完整程式碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <functional>
using namespace std;
//print()傳回值void,參數為空(),待遞迴結束時會呼叫此函式
void print() {
cout << "end" << endl;
}
//print是遞回函式template
//每呼叫一次就從args中拿出一個參數arg,其它的args又傳入print中遞迴呼叫
template<typename T, typename... Args>
void print(T arg, Args... args) {
cout << "參數" << arg << endl;
print(args...);
}
int main() {
print("Bill","Mary","Tom","Allen");
return 0;
}
參數Bill
參數Mary
參數Tom
參數Allen
end
其它函式呼叫遞迴模板,呼叫的函式也要變成模板
以下程式碼為了呼叫遞迴模板,所以本身函式也要變成模板,再把參數傳入遞迴模板
1
2
3
4
5
6
//定義參數的類型名稱Args
template<typename... Args>
void func(const string& school, Args... args) {
cout << school << "的學生有:" << endl;
print(args...);
}
完整程式碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <functional>
using namespace std;
//print()傳回值void,參數為空(),待遞迴結束時會呼叫此函式
void print() {
cout << "end" << endl;
}
//print是遞迴函式template
//每呼叫一次就從args中拿出一個參數arg,其它的args又傳入print中遞迴呼叫
template<typename T, typename... Args>
void print(T arg, Args... args) {
cout << arg << endl;
print(args...);
}
template<typename... Args>
void func(const string& school, Args... args) {
cout << school << "的學生有:" << endl;
print(args...);
}
int main() {
//只有第1個參數傳進func印出來
//第1個參數之後都參數都是args,代入遞迴函式
func("青草湖國小","Bill","Mary","Tom","Allen");
return 0;
}
青草湖國小的學生有:
Bill
Mary
Tom
Allen
end
可變參數模板與bind與functional
寫一個函式可以接收任何種類的函式與不同數量的參數,函式與參數可為左值右值。
以下程式碼不支援函式多載(overload)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <functional>
using namespace std;
class Student {
public:
void print(int code, const string& msg) {
cout << "Error code = " << code << " , Msg = " << msg << endl;
}
};
void print(int code, const string& msg) {
cout << "Error code = " << code << " , Msg = " << msg << endl;
}
template<typename Func, typename... Args>
auto callFunc(Func&& func, Args&&...args)
{
auto f = bind(forward<Func>(func), forward<Args>(args)...);
f();
return f;
}
int main() {
callFunc(print, 400, "Page not found.");
//物件成員函式
Student student;
callFunc(&Student::print, student, 500, "Server error.");
//函式為右值
callFunc([](int code, const string& msg) {
cout << "Lambda error code = " << code << " , Msg = " << msg << endl;
}, 500, "Server error.");
return 0;
}
Error code = 400 , Msg = Page not found.
Error code = 500 , Msg = Server error.
Lambda error code = 500 , Msg = Server error.