- 追加された行はこの色です。
- 削除された行はこの色です。
第8回は可変長テンプレートになります。
今まで可変長引数の関数を作る場合
1: #include <iostream>
2: #include <stdarg.h>
3: using namespace std;
4:
5: void func(int cnt, ...)
6: {
7: va_list ap;
8: va_start(ap, cnt);
9:
10: for (int i = 0; i < cnt; i++)
11: {
12: cout << va_arg(ap, int) << endl;
13: }
14:
15: va_end(ap);
16: }
17:
18: int main()
19: {
20: func(3, 1, 2, 3);
21:
22: return 0;
23: }
このようにva_start、va_arg、va_endを使用していました。(正直可変長引数を普段書かないのでよく分かりません。)
しかし、12行目のva_argの第2引数を見るとわかるように、型の指定がいるため複数の型に対応出来るようにするためには何かしらの型チェックをする必要あって面倒です。
C++11ではテンプレートを可変長で使用することが出来るようになりました。
簡単なプログラム例がこちらになります。
1: #include <iostream>
2: #include <string>
3:
4: using namespace std;
5:
6: template<typename ...T>
7: void func(T... args)
8: {
9: cout << sizeof...(T) << endl;//何個引数あるかはsizeof...で確認
10: }
11:
12: //終端用ダミー
13: void argPrint()
14: {
15: }
16:
17: //unpackすれば可変長以外の引数に渡すことも
18: template<typename T, typename... Arg>
19: void argPrint(T n, Arg... args)
20: {
21: cout << n << endl;
22: argPrint(args...);
23: }
24:
25: int main()
26: {
27: //複数の型を自由に設定出来る
28: func<>();//0
29: func<int>(1);//1
30: func<int, double >(1, 1.0);//2
31: func<int, double, string>(1, 1.0, "Hello");//3
32:
33: //再帰を利用して順番に表示
34: argPrint(1, 1.5, 'c', "Hello");
35:
36: return 0;
37: }
まず、可変長テンプレートを使うには
template<typename... T>
void func(T... arg)
{
//処理
}
従来のtemplateの記述に"..."を追加すればOKです。あとはmain文の部分のように型を指定して書けば使用できます。
さて、可変長テンプレートは0以上の長さのテンプレート(9行目のsizeof...()で確認可能)なのですが、va_argのような機能はないのでそのままでは1つずつ取得することが出来ません。
そのかわり22行目の
argPrint(args...);
のように可変長テンプレートの変数名+"..."と記述することにより、可変長テンプレート以外の引数に渡すことが出来るようになります。(オーバーロードに対しても可)
※ただし、型が決まっている関数に対して渡す場合は型が違うとコンパイルエラーになるので注意。
これをunpackといい、基本的にこれを利用して使用します。
可変長テンプレートは出来ることが多く、私自身がそこまで深く使えないので、今回は簡単な書き方と使用方法のみを説明しました。
可変長テンプレートはC++11の新機能の中でもメインの1つで、他のサイトでも結構扱われているので深く知りたい方は色々探してみてください。(私じゃちょっとキツイです・・・)
以上で可変長テンプレートの説明を終わります。
前→C++11講座7回
次→C++11講座9回
#vote(やだ、C++やだ![0],クルルァに付いて来い[0],ああ逃れられない[0])
#vote(やだ、C++やだ![0],クルルァに付いて来い[0],ああ逃れられない[1])