Class Templateでの型推論
function templateの型推論
function templateでは関数呼び出し時の引数によって型が推論されます
template<typename T> T pow(T a,T b) return (b!=1) ? a : pow(a*a,b-1); } main(){ int a=3,b=3 pow(a,b); //pow<int>と推論される }
class templateの型推論できない?
一方でclass templateは推論することができません
というか,引数とかないので推論するための要素をクラス外から与えられないです
しかしながら、ある特定の条件下では最小のtemplate引数で複数の型を推論させることができます
それがtemplate引数にclass templateを投げた場合です
これによって、ある程度class templateを利用するときの冗長性を排除する事ができます
class templateの冗長性
例えばContainer
その先頭の要素(T型)の値を返すメンバ関数を持っている場合を考えます
以下のように書くとしましょう
template<typename Container,typename T> class N { Container cont_; public: T get(){return cont_.front(); } }; int main() { N<vector<int>,int> n; }
まず、Containerがfront()
を持っているのか?と言うのはコンパイル時に検出できるので無視します
問題はN<vector<int>,int>
のようにint
を2回書かなければならないのが、非常に冗長という事です
これを解決する手法としてテンプレートテンプレートパラメータにする手法が挙げられます
template< template<typename...> class Container,typename T> class N { Container<T> cont_; public: T get(){return cont_.front(); } } int main() { N<vector,int> n; }
しかしこれだと元のclass templateや型引数が分からないtypedef
されたコンテナを渡せなくなります
理想としては、vector<T>
を渡しただけで、T
を推論してほしいところです。
class templateの部分的な型推論
class templateは与えられた型が何かのclass templateだった場合に
そのtemplateの型引数は推論することができます
(ちなみにこれを型推論と言ってよいのか、実はよくわかっておりません)
以下のように書くと勝手にvector<int>
のint
をT
に(こちらが指定することなく推論して)割り当てます
template<typename Container> class N { N(); } // いわゆるclass templateの部分特殊化 template<template<typename...> class Container,typename T, typename... Args> class N< Container<T,Args> > { Container<T> cont_; public: T get(){ return cont_.front(); } }; int main() { typedef vector<int> vec_int; N<vec_int> n; }
上記のようにclass templateの部分特殊化を利用しています
はじめにclass templateだろうがただのclassだろうが
なんでも受取れるようにprimary class template
(特殊化ではないもともとのclass template)を定義します
そして部分特殊化版を書きます
今回書いているのはvector
とかlist
とかに適合するやつです
こうするとvector<T>
やlist<T>
で部分特殊化されるようになります
さらにこの部分特殊化ではvector<int>
のint
は型引数T
に自動的に割り当てられます
これによってSTLコンテナの型引数を自動判別させて、冗長なコードを少なくすることができます
ちなみに、誤って普通のクラスを型引数に代入し、
primary class templateとなってしまった場合を抑制するために
コンストラクタに細工をするのを忘れないようにするとよいです
(上記はコンストラクタが生成できないようにしています)