constexpr な lambda
気がついたら出来ていました。
元々は constexpr 関数内で lambda を使いたかったので、式から型を定義するよな処理を書いていたんですが…。
まだ荒削りですが現状はこんな感じ。
[ソース]
#include <cstddef> #include <tuple> #include <utility> namespace half{ template<std::size_t N> struct placeholder{ template<typename ...Args> constexpr typename std::tuple_element<N, std::tuple<Args...>>::type operator ()(Args... args){ return std::get<N>(std::make_tuple(args...)); } }; namespace arg_names{ typedef placeholder<0> arg1T; typedef placeholder<1> arg2T; typedef placeholder<2> arg3T; typedef placeholder<3> arg4T; typedef placeholder<4> arg5T; constexpr placeholder<0> arg1{}; constexpr placeholder<1> arg2{}; constexpr placeholder<2> arg3{}; constexpr placeholder<3> arg4{}; constexpr placeholder<4> arg5{}; } // namespace arg_names template<typename T, T Value> struct integral_constant{ template<typename ...Args> constexpr T operator ()(Args...) const{ return Value; } }; template<int N> struct int_ : integral_constant<int, N>{}; namespace int_values{ constexpr int_<0> _0i{}; constexpr int_<1> _1i{}; constexpr int_<2> _2i{}; constexpr int_<3> _3i{}; constexpr int_<4> _4i{}; constexpr int_<5> _5i{}; constexpr int_<6> _6i{}; constexpr int_<7> _7i{}; constexpr int_<8> _8i{}; constexpr int_<9> _9i{}; } // namespace int_values template<char C> struct char_ : integral_constant<char, C>{}; namespace char_values{ constexpr char_<'0'> _0c{}; constexpr char_<'1'> _1c{}; constexpr char_<'2'> _2c{}; constexpr char_<'3'> _3c{}; constexpr char_<'4'> _4c{}; constexpr char_<'5'> _5c{}; constexpr char_<'6'> _6c{}; constexpr char_<'7'> _7c{}; constexpr char_<'8'> _8c{}; constexpr char_<'9'> _9c{}; constexpr char_<'a'> _ac{}; constexpr char_<'b'> _bc{}; constexpr char_<'c'> _cc{}; constexpr char_<'d'> _dc{}; constexpr char_<'e'> _ec{}; constexpr char_<'f'> _fc{}; constexpr char_<'g'> _gc{}; constexpr char_<'h'> _hc{}; constexpr char_<'i'> _ic{}; constexpr char_<'j'> _jc{}; constexpr char_<'k'> _kc{}; constexpr char_<'l'> _lc{}; constexpr char_<'m'> _mc{}; constexpr char_<'n'> _nc{}; constexpr char_<'o'> _oc{}; constexpr char_<'p'> _pc{}; constexpr char_<'q'> _qc{}; constexpr char_<'r'> _rc{}; constexpr char_<'s'> _sc{}; constexpr char_<'t'> _tc{}; constexpr char_<'u'> _uc{}; constexpr char_<'v'> _vc{}; constexpr char_<'w'> _wc{}; constexpr char_<'x'> _xc{}; constexpr char_<'y'> _yc{}; constexpr char_<'z'> _zc{}; constexpr char_<'A'> _Ac{}; constexpr char_<'B'> _Bc{}; constexpr char_<'C'> _Cc{}; constexpr char_<'D'> _Dc{}; constexpr char_<'E'> _Ec{}; constexpr char_<'F'> _Fc{}; constexpr char_<'G'> _Gc{}; constexpr char_<'H'> _Hc{}; constexpr char_<'I'> _Ic{}; constexpr char_<'J'> _Jc{}; constexpr char_<'K'> _Kc{}; constexpr char_<'L'> _Lc{}; constexpr char_<'M'> _Mc{}; constexpr char_<'N'> _Nc{}; constexpr char_<'O'> _Oc{}; constexpr char_<'P'> _Pc{}; constexpr char_<'Q'> _Qc{}; constexpr char_<'R'> _Rc{}; constexpr char_<'S'> _Sc{}; constexpr char_<'T'> _Tc{}; constexpr char_<'U'> _Uc{}; constexpr char_<'V'> _Vc{}; constexpr char_<'W'> _Wc{}; constexpr char_<'X'> _Xc{}; constexpr char_<'Y'> _Yc{}; constexpr char_<'Z'> _Zc{}; }; template<typename T> struct val_impl{ template<typename ...args> constexpr T operator ()(args...) const{ return value; } T value; }; template<typename T> constexpr val_impl<T> val(T t){ return {{ t }}; } template<typename T0, typename T1> struct plus{ template<typename ...Args> constexpr auto operator ()(Args... args)->decltype(T0()(args...) + T1()(args...)) const{ return t0(args...) + t1(args...); } T0 t0; T1 t1; }; template<typename T0, typename T1> constexpr plus<T0, T1> operator +(T0 t0, T1 t1){ return { t0, t1 }; } template<typename T0, typename T1> struct minus{ template<typename ...Args> constexpr auto operator ()(Args... args)->decltype(T0()(args...) - T1()(args...)) const{ return t0(args...) - t1(args...); } T0 t0; T1 t1; }; template<typename T0, typename T1> constexpr minus<T0, T1> operator -(T0 t0, T1 t1){ return { t0, t1 }; } template<typename T0, typename T1> struct less_equal{ template<typename ...Args> constexpr bool operator ()(Args... args) const{ return t0(args...) <= t1(args...); } T0 t0; T1 t1; }; template<typename T0, typename T1> constexpr less_equal<T0, T1> operator <=(T0 t0, T1 t1){ return { t0, t1 }; } template<typename T0, typename T1> struct and_{ template<typename ...Args> constexpr bool operator ()(Args... args) const{ return t0(args...) && t1(args...); } T0 t0; T1 t1; }; template<typename T0, typename T1> constexpr and_<T0, T1> operator &&(T0 t0, T1 t1){ return { t0, t1 }; } template<typename Cond, typename Then, typename Else> struct if_else_impl{ template<typename ...Args> constexpr auto operator ()(Args... args)->decltype(Then()(args...)) const{ return cond(args...) ? then(args...) : else_(args...); } Cond cond; Then then; Else else_; }; template<typename Cond, typename Then, typename Else> constexpr if_else_impl<Cond, Then, Else> if_else(Cond cond, Then then, Else else_){ return { cond, then, else_ }; } } // namespace half #include <iostream> #include <cassert> constexpr int ctoi(char c){ using namespace half::arg_names; using namespace half::int_values; using namespace half::char_values; // constexpr な関数内で lambda を定義してみたり typedef decltype(_0c <= arg1 && arg1 <= _9c) isdigit; typedef decltype(_ac <= arg1 && arg1 <= _zc) islower; typedef decltype(_Ac <= arg1 && arg1 <= _Zc) isupper; return isdigit()(c) ? c - char('0') : islower()(c) ? 10 + (c - char('a')) : isupper()(c) ? 10 + (c - char('A')) : char(-1); } int main(){ using namespace half::arg_names; using namespace half::int_values; using namespace half::char_values; // 基本的には Boost.Lambda と同じように Placeholders 等を使用して式を記述する static_assert((arg1 + arg2)(2, 4) == 6, ""); // 値を記述する場合は、val 関数を使用 static_assert((arg1 + half::val(3))(6) == 9, ""); // if else 文 static_assert(half::if_else(arg1, arg2 + arg2, arg2)(true, 3) == 6, ""); static_assert(half::if_else(arg1, arg2 + arg2, arg2)(false, 3) == 3, ""); // constexpr な値でなければ、実行時に処理される int n = 3; assert((arg1 + half::val(2))(n) == 5); // 式から型を定義して評価を行う typedef decltype(arg1 + arg2) plus; static_assert(plus()(2, 6) == 8, ""); // 実行時にも処理出来る int a = 9, b = 2; assert(plus()(a, b) == 11); // 式を型として定義する場合、値は template で定義する必要がある。 typedef decltype(arg1 - half::int_<4>()) minus; static_assert(minus()(6) == 2, ""); // val 関数の場合は、値が保持されない static_assert(decltype(arg1 - half::val(4))()(6) == 6, ""); // '0' ~ '9' や 0 ~ 9 などは予め用意してある static_assert(decltype(arg1 + _8i)()(3) == 11, ""); typedef decltype(_0c <= arg1 && arg1 <= _9c) isdigit; // typedef decltype(half::char_<'0'>() <= arg1 && arg1 <= half::char_<'9'>() ) isdigit; static_assert(isdigit()('8'), ""); static_assert(!isdigit()('A'), ""); return 0; }
やりたいことは出来たので、個人的には満足した。
比較や演算なんかはひと通り用意したいですね。
さて、使い道はあるのか。
あと C++03 のコードばかり書いていたので、そろそろ C++11 のコードも書いて慣れていきたいですね。
特に rvalue reference 周りの挙動とか処理とか標準ライブラリとか。