前書き
テンプレート関数では明示的にテンプレート引数を指定する場合と, 関数の引数から推測できる場合があります.
非常に簡単な例ではこれ
// A("hoge")の様にTは指定しなくてもよい
template<class T>
T A(T x) { return x; }
// B<int>() の様に明示的に指定する
template<class T>
T B(){ return T(); }
int main(){
A(1); // 引数から推論する
B<int>(); // 明示的に指定
}
今回の本題としては以下の様にテンプレート引数が複数ある場合, 1部だけ省略することが可能かどうかで
結果だけ先に書くとデフォルト引数と同じであとに書いていれば省略可能.
// C<5>("hoge") の様に最初のNは指定するが, Tは引数で推論可能
template<int N, class T>
T C(T x) { return x; }
// Tを先に書いてしまうとエラーとなる
template<class T, int N>
T D(T x) { return x; }
// Tだけ指定して, U, Sは引数で推論可能
template<class T, class U, class S>
T E(U , S ){ return T(); }
// 引数の順番的にTを指定するためにはUも指定しなければならない
template< class U,class T, class S>
T F(U, S) { return T(); }
int main(){
C<5>(1); // ok
D<5>(1); // NG Nを指定したつもりだけど実際はTを指定したと解釈される
E<int>(1.0, "hoge"); // ok
F<int, double>(1, "hoge"); // ok
F<int>(1, "hoge"); // NG Tだけ指定したつもりだけど実際はUを指定したと解釈される
}
どういうときに使うか
あまりいい例ではないですが以下の様にラムダ式と組み合わせる時に使います.
#include <iostream>
#include <array>
using namespace std;
// intを変換するTFunc型のコンバーターと数値Nを渡すと
// 0 ~ N-1の値を変換してstd::arrayにして返す
template<int N, class TFunc>
auto Convert(TFunc&& func) -> decltype(auto)
{
using elem_type = decltype(func(0));
std::array<elem_type, N> ret;
for(auto i = 0; i < N; ++i)
ret[i] = func(i);
return ret;
}
int main()
{
// 0 ~ 4の数値を二乗した配列が返る
// ラムダ式の型はわからないけどNだけ指定すれば後は引数から推論してくれる
auto arr = Convert<5>( [](int i) { return i * i; } );
for(auto i = 0; i < 5; ++ i)
cout << arr[i] << endl;
}
結論
引数から型推論したいテンプレート引数は後ろに定義する.