Home > other >  Make generic Lambda with exactly N arguments
Make generic Lambda with exactly N arguments

Time:07-02

I want to dynamically create math expressions with lambdas, as reviewed here.

using Func = std::function<double(double)>;

Func operator (Func const& lhs, Func const& rhs){
    return [lhs, rhs](double x){
        return lhs(x)   rhs(x);
    };
}

My next goal is to generalize this.

Thanks to this answer I managed to implement a generic type with exactly n arguments. But I do not know - if at all possible - how to specify the lambda arguments.

check it on godbolt

#include <functional>

template <std::size_t, typename T> using alwaysT = T;

    template <typename FLOAT, typename Seq> struct func_struct;

    template <typename FLOAT, std::size_t... Is>
    struct func_struct<FLOAT, std::index_sequence<Is...>> {
        using type = std::function<double(alwaysT<Is, FLOAT>... floats)>;
    };

    template <std::size_t N>
    using func_t = typename func_struct<double, std::make_index_sequence<N>>::type;

    template <std::size_t N>
    func_t<N> operator (func_t<N> const& lhs, func_t<N> const& rhs){
        return [lhs, rhs](alwaysT<N, std::make_index_sequence<N>> args...){// how to do this?
            lhs(args)   rhs(args);
        };
    }

int main(){
    func_t<1> f1 = [](double x){return x*2;};
    func_t<2> f2 = [](double x, double y){ return x*y;};

    func_t<1> f3 = f1   f1;


}

I'm also getting an error that the template argument N can not be deduced, in the last line.

CodePudding user response:

Not sure the standard allows you to manage argument count restriction like that, but you can definitely have an assert if the arg count is in mismatch. E.g.:

#include <functional>

template <std::size_t, typename T> using alwaysT = T;

    template <typename FLOAT, typename Seq> struct func_struct;

    template <typename FLOAT, std::size_t... Is>
    struct func_struct<FLOAT, std::index_sequence<Is...>> {
        using type = std::function<double(alwaysT<Is, FLOAT>... floats)>;
    };

    template <std::size_t N>
    struct func_t : func_struct<double, std::make_index_sequence<N>>::type {
        using Base = typename func_struct<double, std::make_index_sequence<N>>::type;
        using Base::Base;
    };

    template <std::size_t N>
    func_t<N> operator (func_t<N> const& lhs, func_t<N> const& rhs){
        return [lhs, rhs](auto&&... args){
            return lhs(args...)   rhs(args...);
        };
    }

int main(){
    func_t<1> f1 = [](double x){return x*2;};
    func_t<2> f2 = [](double x, double y){ return x*y;};

    func_t<1> f3 = f1   f1;
}

Note, I've changed the template<size_t N> using func_t to a template<size_t N> struct func_t so that matching on template argument is possible. using declarations are always replaced before matching and the compiler (as per current standard) is not expected to be able to deduce N from <double, 0, 1, 2, ...>.

  • Related