blog:2016:2016-01-20

差分

このページの2つのバージョン間の差分を表示します。

この比較画面にリンクする

次のリビジョン
前のリビジョン
blog:2016:2016-01-20 [2016-01-20 13:45]
Decomo 作成
blog:2016:2016-01-20 [2016-01-20 14:51] (現在)
Decomo
行 3: 行 3:
 新年明けましておめでとうございます(遅。開設14年目となるクソゲ~製作所を本年もよろしくお願い致します。 新年明けましておめでとうございます(遅。開設14年目となるクソゲ~製作所を本年もよろしくお願い致します。
  
-C++のテンプレートには特殊化という、特定のテンプレト引数の時にテンプレートの実体を別に定義する機能がある。だが、C#版テンプレートとも言えるジェネリックでは、なんということでしょう、特殊化が使えないではありませんか!+C++のテンプレートには特殊化という、特定の型パラメの時にテンプレートの実体を別に定義する機能がある。だが、C#版テンプレートとも言えるジェネリックでは、なんということでしょう、特殊化が使えないではありませんか!それをどうにかしてジェネリック特殊化っぽい事をしてみたっていうお話。
  
 こんなコードがあったとする。 こんなコードがあったとする。
行 81: 行 81:
  
 文章を模したデータ構造を作り、''FindChildren''メソッドで型をパラメータに子ノードを取得しているが、 文章を模したデータ構造を作り、''FindChildren''メソッドで型をパラメータに子ノードを取得しているが、
-''doc.FindChildren<SectionNode>()''は正しい挙動をするものの、''doc.FindChildren<TitleNode>()''の方は空のリストが帰ってくる。''FindChildren()''は''Node.Children''しか見てないので、''SectionNode.Title''が入るはず+''doc.FindChildren<SectionNode>()''は正しい挙動をするものの、''doc.FindChildren<TitleNode>()''の方は空のリストが帰ってくる。''FindChildren()''は''Node.Children''しか見てないので、独立したメンバ''SectionNode.Title''が入るはずく当然の挙動である
  
-こんな時、C++なら特殊化で''FindChildren<TitleNode>''専用の処理書けるのだが、ジェネリックは特殊化が使えないので処理が書けない。C#的には''FindChildTitleNodes()''的な別メソッドで提供するのが正しいのかもしれないが、統一感に欠けるじゃないですかやだー!(そもそもこんな糞いデータ構造にすんなって話だが例ってことで許してね。)+こんな時、C++なら特殊化で''FindChildren<TitleNode>''専用の処理書け同一のインタフェースを提供できるのだが、前述の通りジェネリックは特殊化が使えないの。C#的には''FindChildTitleNodes()''的な別メソッドで提供するのが正しいのかもしれないが、やっぱり統一感に欠けて美しくない(そもそもこんな糞いデータ構造にすんなって話だが例ってことで許してね。)
  
 で、知恵を振り絞って''FindChildren''を以下のようにした。 で、知恵を振り絞って''FindChildren''を以下のようにした。
行 120: 行 120:
  
 元の''FindChildren()''を''FindChildrenInternal()''とし、''FindChildren()''には型パラメータ''T''に応じた処理を書くようにした。C++でコンパイラが自動で行ってくれる特殊化による処理の振り分けを、実行時に手動で行うような感じかしら。原理上、実行時コストは増えるが、この程度なら大した影響はないだろう。JIT様もあることだし。 元の''FindChildren()''を''FindChildrenInternal()''とし、''FindChildren()''には型パラメータ''T''に応じた処理を書くようにした。C++でコンパイラが自動で行ってくれる特殊化による処理の振り分けを、実行時に手動で行うような感じかしら。原理上、実行時コストは増えるが、この程度なら大した影響はないだろう。JIT様もあることだし。
 +
 +型が増えると''if''と特殊化処理の嵐になるが、型ごとに処理デリゲートを作って''Type''とデリゲート辞書でも作ればすっきりするので大した問題ではない。そもそも、そんな状況は最早「特殊化」の本質から外れてるので設計から見直すべきだろう。
  
 このコードのミソは(1)~(3)の部分。 このコードのミソは(1)~(3)の部分。
  
-(1)で処理すべき''T''の型が明確になったものの、(2)-aで''List<T>''としているのはコンパイルを通すため。''List<TitleNode>''でも良さそうに見えるが、''T == TitleNode''になるとは限らないので(2)-bで型不一致エラーになる。+(1)で処理すべき''T''の型が明確になったものの、(2)-aで''List<T>''としているのはコンパイルを通すため。''List<TitleNode>''でも良さそうに見えるが、''T == TitleNode''になるとは限らないので(2)-bで型不一致エラーになる。''List<TitleNode>''とした場合に''T = SectionNode''で呼び出した時にどうなるかを考えれば、すぐにおかしさに気づいて頂けるかなと
  
 (3)も一見''titles.Add(e.Title)''で良さそうだが、これまた''TitleNode''が必ずしも''T''に変換可能とは限らないのでCS1503エラーとなる。よって、ちょっとアホくさいが''TitleNode''を自身の型''T''にキャストしてやらなければならない。 (3)も一見''titles.Add(e.Title)''で良さそうだが、これまた''TitleNode''が必ずしも''T''に変換可能とは限らないのでCS1503エラーとなる。よって、ちょっとアホくさいが''TitleNode''を自身の型''T''にキャストしてやらなければならない。
  • blog/2016/2016-01-20.1453265125.txt.gz
  • 最終更新: 2016-01-20 13:45
  • by Decomo