How can currying be done in C++?

前端 未结 10 1393
余生分开走
余生分开走 2020-11-28 03:39

What is currying?

How can currying be done in C++?

Please Explain binders in STL container?

10条回答
  •  情深已故
    2020-11-28 04:16

    I implemented currying with variadic templates as well (see Julian's answer). However, I did not make use of recursion or std::function. Note: It uses a number of C++14 features.

    The provided example (main function) actually runs at compile time, proving that the currying method does not trump essential optimizations by the compiler.

    The code can be found here: https://gist.github.com/Garciat/c7e4bef299ee5c607948

    with this helper file: https://gist.github.com/Garciat/cafe27d04cfdff0e891e

    The code still needs (a lot of) work, which I may or may not complete soon. Either way, I'm posting this here for future reference.

    Posting code in case links die (though they shouldn't):

    #include 
    #include 
    #include 
    #include 
    
    // ---
    
    template 
    struct function_traits;
    
    template 
    struct function_traits {
        using arity = std::integral_constant;
    
        using result_type = RType;
    
        template 
        using arg_type = typename std::tuple_element>::type;
    };
    
    // ---
    
    namespace details {
        template 
        struct function_type_impl
          : function_type_impl
        { };
    
        template 
        struct function_type_impl {
            using type = RType(ArgTypes...);
        };
    
        template 
        struct function_type_impl {
            using type = RType(ArgTypes...);
        };
    
        template 
        struct function_type_impl> {
            using type = RType(ArgTypes...);
        };
    
        template 
        struct function_type_impl {
            using type = RType(ArgTypes...);
        };
    
        template 
        struct function_type_impl {
            using type = RType(ArgTypes...);
        };
    }
    
    template 
    struct function_type
      : details::function_type_impl::type>::type>
    { };
    
    // ---
    
    template 
    struct apply_args;
    
    template 
    struct apply_args, std::tuple>
      : std::enable_if<
            std::is_constructible::value,
            apply_args, std::tuple>
        >::type
    { };
    
    template 
    struct apply_args, std::tuple> {
        using type = std::tuple;
    };
    
    // ---
    
    template 
    struct is_empty_tuple : std::false_type { };
    
    template <>
    struct is_empty_tuple> : std::true_type { };
    
    // ----
    
    template 
    struct currying;
    
    template 
    struct currying, std::tuple> {
        std::tuple given_args;
    
        FType func;
    
        template 
        constexpr
        currying(Func&& func, GivenArgsReal&&... args) :
          given_args(std::forward(args)...),
          func(std::move(func))
        { }
    
        template 
        constexpr
        auto operator() (Args&&... args) const& {
            using ParamsTuple = std::tuple;
            using ArgsTuple = std::tuple;
    
            using RestArgsPrime = typename apply_args::type;
    
            using CanExecute = is_empty_tuple;
    
            return apply(CanExecute{}, std::make_index_sequence{}, std::forward(args)...);
        }
    
        template 
        constexpr
        auto operator() (Args&&... args) && {
            using ParamsTuple = std::tuple;
            using ArgsTuple = std::tuple;
    
            using RestArgsPrime = typename apply_args::type;
    
            using CanExecute = is_empty_tuple;
    
            return std::move(*this).apply(CanExecute{}, std::make_index_sequence{}, std::forward(args)...);
        }
    
    private:
        template 
        constexpr
        auto apply(std::false_type, std::index_sequence, Args&&... args) const& {
            using ParamsTuple = std::tuple;
            using ArgsTuple = std::tuple;
    
            using RestArgsPrime = typename apply_args::type;
    
            using CurryType = currying, RestArgsPrime>;
    
            return CurryType{ func, std::get(given_args)..., std::forward(args)... };
        }
    
        template 
        constexpr
        auto apply(std::false_type, std::index_sequence, Args&&... args) && {
            using ParamsTuple = std::tuple;
            using ArgsTuple = std::tuple;
    
            using RestArgsPrime = typename apply_args::type;
    
            using CurryType = currying, RestArgsPrime>;
    
            return CurryType{ std::move(func), std::get(std::move(given_args))..., std::forward(args)... };
        }
    
        template 
        constexpr
        auto apply(std::true_type, std::index_sequence, Args&&... args) const& {
            return func(std::get(given_args)..., std::forward(args)...);
        }
    
        template 
        constexpr
        auto apply(std::true_type, std::index_sequence, Args&&... args) && {
            return func(std::get(std::move(given_args))..., std::forward(args)...);
        }
    };
    
    // ---
    
    template 
    constexpr
    auto curry(FType&& func, std::index_sequence) {
        using RealFType = typename function_type::type;
        using FTypeTraits = function_traits;
    
        using CurryType = currying, std::tuple...>>;
    
        return CurryType{ std::move(func) };
    }
    
    template 
    constexpr
    auto curry(FType&& func) {
        using RealFType = typename function_type::type;
        using FTypeArity = typename function_traits::arity;
    
        return curry(std::move(func), std::make_index_sequence{});
    }
    
    // ---
    
    int main() {
        auto add = curry([](int a, int b) { return a + b; });
    
        std::cout << add(5)(10) << std::endl;
    }
    

提交回复
热议问题