Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

実践Type erasure

プロジェクト内の勉強会で発表した、C++のType Erasureという手法について紹介します

  • Be the first to comment

  • Be the first to like this

実践Type erasure

  1. 1. 実践Type Erasure 2016/01/21 土江智明
  2. 2. 目次 Type Erasureとは 簡単な説明 std::functionを使った例 Type Erasureの活用 Boost.TypeErasureの使い方・使いドコロ もっと便利にTypeErasure 汎用的に使えるコンセプトを作っておく 自動でモック生成
  3. 3. この発表について C++の話です テンプレートと継承を知ってる人向け 内容 Type Erasureとは何か どう便利に使うか Type Erasureの実装には触れません
  4. 4. この資料中で使う用語の定義 コンセプト ある名前のメンバ関数をもつ、等の型に対する制約 インターフェース あるコンセプトを満たす型を格納できる型
  5. 5. Type Erasure とは
  6. 6. 簡単な説明 インターフェースを作成するテクニック プロジェクトのコードでもちょっと使ってます 継承とテンプレートを組み合わせて作る もしくは仮想関数テーブル自作(今回は触れない) 標準ライブラリでの使用例 function shared_ptrのdeleter
  7. 7. std::functionの解説
  8. 8. std::functionとは 関数っぽく振る舞う何かを格納する型 「呼び出し可能」な型を格納できるインターフェース 「呼び出し可能」な型→Callable Conceptを満たす型 void register(function<int(string)> callback){ // process callback(“hogefuga”); }
  9. 9. Conceptとは 型の満たす特性を示したもの 呼び出し可能 コピー可能 足し算・引き算が可能 ... C++の規格書のなかにもたくさんある Boostの中にもたくさんある Rangeとか
  10. 10. 呼び出し可能なオブジェクト Callable Conceptを満たすもの 関数、関数オブジェクト、ラムダ式 void register(function<int(string)> callback); void onFinish(string str); register(onFinish);
  11. 11. 呼び出し可能なオブジェクト Callable Conceptを満たすもの 関数、関数オブジェクト、ラムダ式 void register(function<int(string)> callback); struct OnFinish{ void operator()(string str); } instance; register(instance);
  12. 12. 呼び出し可能なオブジェクト Callable Conceptを満たすもの 関数、関数オブジェクト、ラムダ式 void register(function<int(string)> callback); register( [](string str){ cout << str << endl; } );
  13. 13. std::functionの実装 std::functionはType Erasureで実現されている Type Erasureは 継承 + テンプレート で実現 仮想関数テーブルを自作する方法もある(省略) std::functionと同様のことを… 継承だけで実現しようとしたらどうなるか テンプレートだけで実現しようとしたらどうなるか
  14. 14. 継承によるfunctionの実装 class CallableInterface { virtual void operator()(string str) = 0; }; void register(CallableInterface & callback); class OnFinish : public CallableInterface { void operator()(string str) override; } instance; register(instance);
  15. 15. 継承による実装の短所 基底となるクラスの定義が必要 コールバックに渡すものはソレを継承する 書くのがめんどくさい 参照かポインタでしか渡せない(Slicing防止) フリー関数やラムダ式を渡せない std::plus等の関数オブジェクトも渡せない
  16. 16. テンプレートによるfunctionの実装 template <class Callable> void register(Callable callback); class OnFinish /* 継承しなくて良い */ { void operator()(string str) override; } instance; register(instance);
  17. 17. テンプレートによる実装の短所 実装を全部ヘッダに書かないといけない 再コンパイルの対象ファイルが多くなり時間がかかる バイナリサイズが大きくなりがち 動的に型を切り替えられない 全て静的に解決するため、Templateだらけに… エラーメッセージが分かりにくくなりがち コンセプトを何故満たさないかわかりにくい Boost.ConceptCheck等使えばまだマシ
  18. 18. Type Erasureによる実装の長所 継承版とテンプレート版の良いとこ取り 実装をヘッダに書かなくて良い 動的に型を切り替えられる エラーが見易い(気がする) 基底となるクラス等はいらない 参照・ポインタでなく値で渡すことができる フリー関数もラムダ式も渡せる
  19. 19. Type Erasureによる実装の短所 実行時のオーバーヘッドはある程度大きい 気になるときはテンプレート版に書きなおそう
  20. 20. Type Erasureの活用
  21. 21. Type Erasureの活用 std::functionは呼び出し可能オブジェクトだけ →もっと色んなオブジェクトを表現したい… 列挙可能(Enumerable)とか Serializableとか そこで、Boost.TypeErasureを使う
  22. 22. Boost.TypeErasureとは Boostライブラリに1.54で入ったモジュール ある操作ができる何かを格納するクラス std::functionは「呼び出し可能」な何か using concepted_type = // 型に別名をつける type_erasure::any<mpl::vector< // ここにコンセプトを列挙する >>;
  23. 23. Boost.TypeErasure使用例 「void(string), void(int)で呼び出し可能」 失敗と成功のコールバックのペア…とかやる時に便利 using multi_function = any<mpl::vector< callable<void(string)>, callable<void(int)> >>; void register(multi_function callback) // 例
  24. 24. Boost.TypeErasure使用例 「足し算引き算できる」 int, double, duration… using additive = any<mpl::vector< addable<>, substractable<> >>;
  25. 25. Boost.TypeErasure使用例 「publish(int)メンバ関数を持つ」 ある名前のメソッドのコンセプトを作るマクロがある BOOST_TYPE_ERASURE_MEMBER( (publishable), publish, 0) using additive = any<mpl::vector< publishable<void(int)> >>;
  26. 26. 実際の使用シーン コールバックの登録等 std::functionより複雑な型が登録できる モックを使ったテストが書きたい時 コンセプトに合う型を作ってモックとして渡す
  27. 27. もっと便利にType Erasure
  28. 28. もっと便利にTypeErasure TypeErasureを便利にプロジェクトで使いたい 汎用的に使えそうなものを定義しておく Enumerable<T> Comparable<T> コンセプトからモックの自動生成をする そういうライブラリをこっそり作りました
  29. 29. コンセプトからモックの自動生成をす る Boost.TypeErasureはコンセプトを列挙する コンセプトからMockを自動生成できそう…? TypeErasureで受け取ってる型をテストできる using concepts = mpl::vector< // ここにコンセプトを列挙する >>; mock_type<concepts> mock;
  30. 30. コンセプトからモックの自動生成をす る Mockを生成するライブラリ?を書きました gmockにだけ対応してます 対応できないコンセプトがいくつかあります constructibleとかはちょっと厳しい… void register(any<concepts> callback); mock_type<concepts> mock; register(mock);
  31. 31. まとめ TypeErasureはインターフェースを定義する 継承によるインターフェースよりも… 書きやすい 組み込み型・標準ライブラリの型にも対応できる テンプレートによるインターフェースより… エラーが見やすい コンパイルが早い Boost.TypeErasure便利

×