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 周りの挙動とか処理とか標準ライブラリとか。