テンプレートで型情報を作る
C++勉強ネタです
テンプレートを使って、関数型言語の型情報を生成してみます(やっつけなのでバグがあるかも)
値型はValue, λ抽象はArrowになっています。 とりあえずValueには設定された文字列を格納し、Arrowは単にリストを作ってるだけです。
型Tが関数型を持つ場合は、std::tuple
にシグネチャを格納しておきます
静的変数のアドレスはconstexpr
として、初期化前に取得することができます。
依存関係のある静的変数を初期化するのって大変ですよね…
staticローカル変数を使っても良いのですが、そうすると初期化が再帰してUBになるかもです
#include <tuple> #include <iostream> #include <variant> #include <cassert> template <class T> struct traits; // value type struct Value; // arrow type struct Arrow; // union using Type = std::variant<Arrow,Value>; struct Arrow{ Type* captured; Type* returns; }; struct Value{ const char* name; }; template <class T> struct value_type{ static Type type; }; // arrow_type impl template <class T, class ...Ts> struct arrow_type_{ static Type type; }; // arrow_type impl template <class T1, class T2> struct arrow_type_<T1,T2>{ static Type type; }; template <class T, class ...Ts> struct arrow_type; template <class T, class ...Ts> struct arrow_type<T, std::tuple<Ts...>>{ static constexpr Type* type = &arrow_type_<Ts...>::type; }; template <class T, class = void> struct object_type { static constexpr Type* type = arrow_type<T,typename T::type>::type; }; template <class T> struct object_type<T, std::void_t<decltype(traits<T>::name)>>{ static constexpr Type* type = &value_type<T>::type; }; template <class T> Type value_type<T>::type {Value{traits<T>::name}}; template <class T, class ...Ts> Type arrow_type_<T,Ts...>::type {Arrow{ object_type<T>::type, &arrow_type<Ts...>::type }}; template <class T1, class T2> Type arrow_type_<T1,T2>::type {Arrow{object_type<T1>::type, object_type<T2>::type}}; // define int type template <> struct traits<int>{ static constexpr const char* name = "int"; }; int main () { struct foo{ // basic closure type (int->int) using type = std::tuple<int,int>; }; struct bar{ // recursive closure type (bar->int) using type = std::tuple<bar,int>; }; // value auto i = object_type<int>::type; std::cout << std::get<Value>(*i).name << std::endl; // int // closure auto f = object_type<foo>::type; assert(std::get<Arrow>(*f).captured == i); assert(std::get<Arrow>(*f).returns == i); // recursive auto b = object_type<bar>::type; assert(b == std::get<Arrow>(*b).captured); return 0; }