CADDi C++勉強会に参加した
CADDiさんが開催しているC++勉強会に参加してきたので,その覚書.
- type eraser
- expression template
についての話.
type eraser
type eraserは,型情報を隠すためのテクニック.
テンプレートを利用して,コーディングする際に型を気にしないで済むようにしたもの.日本語だと型消去とか呼ばれてたりするらしい.
C++17以降の標準ライブラリにはstd::any
がある.以下のように,様々な型のオブジェクトを代入することができる.
#include <iostream> #include <any> #include <vector> #include <algorithm> #include <string> int main() { std::any a = 1; // intのリテラルを代入 std::cout << std::any_cast<int>(a) << std::endl; // 1 a = std::string("this is string"); // 文字列を代入 std::cout << std::any_cast<std::string>(a) << std::endl; auto vec = std::vector<int>(10); for(std::size_t i=0;i<vec.size();i++) vec.at(i) = i; a = vec; std::any b = a; auto v = std::any_cast<std::vector<int>>(b); for_each(v.begin(), v.end(), [](auto x){ std::cout << x << " ";}); return 0; }
C言語でいうvoid*
に相当する.
anyの実装例
型消去テクニックを使って実装する.このテクニックは他で活かせる場面がなかなかない(というか多分ない)とのこと.
大切だと思うのは2点あって,
- anyクラスのコンストラクタをテンプレートにしておいて,コンストラクタの引数の型からテンプレートの型を推論させるところ
- anyクラスは値を直接持つのではなく,テンプレートクラスで値をラップして保持する.テンプレートクラスはポリモフィックでanyクラスがうまく保持できるようになっているところ
以下に実装例を示す.
// 基底クラス. struct any_base { virtual ~any_base() {} }; // anyに渡された値を保持するテンプレートクラス // any_baseを継承しているので,anyクラスでは基底クラスとしてメンバを定義する template<class T> struct any_holder : public any_base { any_holder(const T &value) : _value(value) {} T _value; }; // anyクラス // anyクラスはテンプレートクラスではない class any { public: template<class T> any(const T& value) { // コンストラクタ引数からテンプレート引数Tを推論 // holderクラスに値を渡して保持 _base = new any_holder<T>(value); } ~any() { delete _base; } any_base *_base; }; // anyクラスから値を取り出すキャスト // 本当はanyの持つクラスとテンプレート引数Tが同じであるかを // チェックする必要がある template<class T> T any_cast(any &a) { return static_cast<any_holder<T>*>(a._base)->_value; }; int main() { any a = std::string("aaaa"); std::cout << any_cast<std::string>(a) << std::endl; any b = 1; std::cout << any_cast<int>(b) << std::endl; }
expression template
四則演算などの計算式をテンプレートとして表現し,コンパイル時に展開してもらう,というもの.
式の評価の遅延などに使える,らしい.
かなり駆け足での説明だったので,メモを取る時間がなかったので割愛.
どこかで資料を見つけたらまとめておこう.