タグ・ディスパッチ(tag dispatch)とトレイツ(traits)
ふつーにテンプレート使って型に応じた処理をオブジェクト指向っぽく書くと、静的にポリモーフィズムれるんだけど、そのほかにも掲題の「タグ・ディスパッチ」って手法もあるらしい。
タグ付けして処理をグルーピングさせるために使うイメージ。有名所だとSTLのiterator周り、advance関数の処理切り替えとかだそうだ。
正直、この辺の名前
の区別や以下の書き方両方ともタグディスパッチ言うのかかなり怪しい。
クラスの中でタグをtypedefしてそのタグに応じて処理を振り分ける書き方。
#include<iostream> //Tag用の構造体 struct TagA{}; struct TagB{}; //クラスの定義 class Hoge1 { public : typedef TagA tag; }; class Hoge2 { public : typedef TagA tag; }; class Hoge3 { public : typedef TagB tag; }; //Tagに応じた処理 template<class T> void process(T &x, TagA){std::cout<<"Tag A is done"<<std::endl;} template<class T> void process(T &x, TagB){std::cout<<"Tag B is done"<<std::endl;} //コンパイル時にタグAかタグBか見極めて処理振り分ける template<typename T> void process(T & x) { process(x, typename T::tag()); } //テスト int main() { process(Hoge1()); process(Hoge2()); process(Hoge3()); }
実行結果
Tag A is done Tag A is done Tag B is done
traitsクラスを作ってそれのテンプレート特化で処理を分ける方法もある。
#include<iostream> //タグ struct tag_algorithm_A{}; struct tag_algorithm_B{}; //適当自作クラス class Hoge{}; //traitsクラス(デフォルトはアルゴリズムA) template<class T> struct traits{ typedef tag_algorithm_A algorithm; }; //traitsクラス(Hoge型はアルゴリズムB) template<> struct traits<Hoge>{ typedef tag_algorithm_B algorithm; }; //タグごとの処理 template<class T> void run(const T & x, tag_algorithm_A){ std::cout << "Algorithm A is run." << std::endl; } template<class T> void run(const T & x, tag_algorithm_B){ std::cout << "Algorithm B is run." << std::endl; } //タグごとに処理を切り替えて実行 template<class T> void run(const T & x){ run(x, traits<T>::algorithm()); } //main int main() { int x; double y; Hoge z; //タグを指定して処理を変える run(x, tag_algorithm_A()); run(x, tag_algorithm_B()); //タグによる自動切り分け(タグディスパッチ) run(x); run(y); run(z); return 0; }
実行結果
Algorithm A is run. Algorithm B is run. Algorithm A is run. Algorithm A is run. Algorithm B is run.
参考
アヒルの判別
traits と tag dispatching – こたつつきみかん rev.2
Tag dispatching | efesx
traitsとtag dispatchがわかった - 三次元日誌