constexpr な bind1st

ついでにカリー化も。

[ソース]

#include <functional>
#include <type_traits>


namespace aliases{

template<typename T>
using remove_reference = typename std::remove_reference<T>::type;

}  // namespace aliases


template<typename F, typename First>
struct bind1st_impl{
    template<typename ...Args>
    constexpr auto
    operator ()(Args&&... args) const
    ->decltype(std::declval<F>()(std::declval<First>(), std::forward<Args>(args)...)){
        return func(first, std::forward<Args>(args)...);
    }
    F func;
    First first;
};


template<typename F, typename First>
constexpr bind1st_impl<F, aliases::remove_reference<First>>
bind1st(F func, First&& first){
    return { func, std::forward<First>(first) };
}



template<typename F>
struct curry_impl{
    template<typename T>
    constexpr operator T() const{
        return func();
    }
    
    template<typename First>
    constexpr curry_impl<bind1st_impl<F, aliases::remove_reference<First>>>
    operator ()(First&& first) const{
        return { ::bind1st(func, std::forward<First>(first)) };
    }
    
    F func;
};

template<typename F>
constexpr curry_impl<F>
curry(F func){
    return { std::forward<F>(func) };
}


struct plus{
    template<typename T>
    constexpr aliases::remove_reference<T>
    operator ()(T&& t) const{
        return std::forward<T>(t);
    }

    template<typename T, typename ...Args>
    constexpr aliases::remove_reference<T>
    operator ()(T&& t, Args&&... args) const{
        return std::forward<T>(t)
             + (*this)(std::forward<Args>(args)...
        );
    }
};

constexpr int
minus(int a, int b, int c){
    return a - b - c;
}


int
main(){
    constexpr auto plus3 = bind1st(plus(), 3);
    static_assert(plus3( 2) == 5, "");
    static_assert(plus3(-3) == 0, "");

    static_assert(bind1st(bind1st(minus, 10), 4)(2), "");
    static_assert(bind1st(bind1st(plus(), 10), 5)() == 15, "");

    constexpr int result = curry(&minus)(3)(2)(1);
    static_assert(result == 0, "");

    constexpr int result2 = curry(plus())(3)(2)(1)(-4);
    static_assert(result2 == 2, "");

    return 0;
}


こんな感じであっているかしら?
そういえば、メソッドのこととかあんまり考えていないなー。

[コンパイラ]

  • g++ (GCC) 4.7.0 20111210 (experimental)