C++テンプレートの型推論

C++のテンプレートの動作について、確認のつもりでちょっといろいろやってみたら、いままで知らなかった動作に出会えた。

template<class T>
T op(T (*fun)(T, T), T s1, T s2) { return (*fun)(s1, s2); };

template<class T>
T add(T s1, T s2) { return s1 + s2; };

とテンプレートを定義しているとき、

op<int>(add<int>, 1, 1);
op(add, 1, 1);

は、どちらもコンパイルできるし、テンプレートの型推論が働いて両者は等価になる。これはC++のテンプレートの動作としてちゃんと定義されている。

で、opの型とその引数の型をより自由にするために、

template<class T1, class T2, class T3>
T1 op(T1 (*fun)(T2, T3), T2 s1, T3 s2) { return (*fun)(s1, s2); };

とすると、

op(add, 1, 1);

では op の型(もしくは *add の型)が分からないので、当然エラーになる。この場合、

op<int, int, int>(add, 1, 1);
op(add<int, int, int>, 1, 1);

のどちらかにするのが、お行儀の良いやりかた。

ところがC++のテンプレートの型推論は思ってたよりも優秀で、

op<int>(add, 1, 1);

でも、ちゃんとコンパイルが通った。これはすごい。全ての型が推論できないときは、型引数全てを与えなければいけないものだと思っていたら、そうでもなかった。省略された型引数のみを型推論するこの動作は、関数のデフォルト引数の動作に良く似ている。

コレ、型引数の追加を忘れていてたまたま出会ったもの。失敗とは偉大だ。

ちなみに、

op(add<int>, 1, 1);

はエラー。