読者です 読者をやめる 読者になる 読者になる

わくわくとオーボエ

プログラミングの話題とかとか

C++で型クラスっぽいこと - Traits

背景

昨日(一昨日か)の型クラス勉強会に参加してきました。
ただ、残念ながら自分はScalaHaskellもSMLも明るくないしUr/Webとかいうのは初耳だったので、整理を兼ねて++で型クラスっぽい実装を。
(C++分かるとか書いたらいろいろ飛んできそうなのでそんなことは書けないのですが)

@k_katsumiさんの発表(https://speakerdeck.com/kishikawakatsumi/type-classes-in-swift)をまねて、シーザー暗号の関数を作ってみました。

目的

  • Traitsの使い方を(自分が)理解する
  • 他言語での型クラスのありがたみを理解する

ソース

何やってるの?

最初にこういうコードを見た時はギョッとしました(・д・)が、昨日Swiftのコードを見た後にこれを考えたら以外とスッキリ。自分なりの考え方としては以下の通り。

  1. 最終的に encodeInCaesar(123) や encodeInCaesar("hoge")の形で呼び出せるtemplate関数encodeInCaesar(T t)を作りたい。つまり引数の型Tによって、内部の処理を分岐させたい。
  2. 対象の型ごとに処理が変わるように特殊化された型CaesarTraits<T>を用意する。encodeInCaesar(T t)の中でCaesarTraits<T>を使えば処理の分岐ができる。
  3. 特殊化しなかったらコンパイルエラーになるように、基本のCaesarTraits<T>では何もメンバ関数を定義しない。

CaesarTraits<T> を通してデータにアクセスするという取り決めがSwiftのprotocol定義、CaesarTraits<T>を対象の型ごとに特殊化するというのがSwiftのExtension定義に相当してます。

C++のtemplateはダックタイピング的で、使い方が同じあれば型の意味とか関係なくコンパイルできてしまいます。一方で、templateは特殊化することで、特定の型について別の挙動を与えることができます。前者がparametric polymorphism、後者がad-hoc polymorphism。encodeInCaesar()関数はparametric polymorphismを利用していて、その先では実はad-hoc polymorphismになっている。だから全体としてはad-hocに振る舞う。
という認識なんですが、合ってますかね(・o・)??

まとめ

  1. 落ち着いて考えたらC++でもTraits使って型クラス的なものが書けた。
  2. でも書くのちょっと大変だしコンパイルエラーがわかりにくくて辛いのではやく文法としてのConcept (http://en.cppreference.com/w/cpp/language/constraints) がほしい。Conceptが採用されるとコンパイラの解析が楽になってエラーも見やすくなるはずなのだけど…いつ正式採用されるのかな...

その他

Wordpress.comでたまーに書いてたんですけど、ちょっとはてなブログに移ってきてみました。間違ったこと書いてそのままなのは良くないと思うので、優しいマサカリをお願いします。

参考

  1. https://speakerdeck.com/kishikawakatsumi/type-classes-in-swift
  2. http://faithandbrave.hateblo.jp/entry/20110318/1300427444
  3. http://faithandbrave.hateblo.jp/entry/20130226/1361862112