Search code examples
c++c++11function-templatespartial-applicationtype-deduction

function templates, partial application and template argument deduction


I try to get the following main function to compile and work like expected:

int main()
{
    auto square = [](int x){ return x*x; };

    typedef std::vector<int> Row;
    typedef std::vector<Row> Mat;
    Mat mat;
    auto squareElements = Curry(Map<Row>, square);
    Mat squaredMat = Map<Mat>(squareElements, mat);
}

Right now my supplementary code looke like this:

#include <algorithm>
#include <functional>
#include <iterator>
#include <vector>

template <typename ContainerOut, typename ContainerIn, typename F>
ContainerOut Map( const F& f, const ContainerIn& xs )
{
    ContainerOut ys;
    // For performance reason one would use
    // ys.reserve( xs.size() )
    // and std::back_inserter instead of std::inserter
    // if ys is a std::vector.
    auto it = std::inserter( ys, end( ys ) );
    std::transform( begin( xs ), end( xs ), it, f );
    return ys;
}

template <typename Ret, typename Arg1, typename ...Args>
auto Curry( Ret f(Arg1, Args...), Arg1 arg ) -> std::function<Ret(Args...)>
{
    return [=]( Args ...args ) { return f( arg, args... ); };
}

and it does not compile.

Any idea how one can make the compiler deduce the template parameters?


Solution

  • One possible solution to avoid having to use std::placeholders::_1 with std::bind every time.

    #include <algorithm>
    #include <functional>
    #include <iterator>
    #include <utility>
    #include <vector>
    
    template <typename Container, typename F>
    Container Map( const F& f, const Container& xs )
    {
        Container ys;
        // For performance reasons one would use
        // ys.reserve( xs.size() )
        // and std::back_inserter instead of std::inserter
        // if ys is a std::vector.
        auto it = std::inserter( ys, end( ys ) );
        std::transform( begin( xs ), end( xs ), it, f );
        return ys;
    }
    
    template <typename F, typename T>
    auto Curry(F&& f, T&& t)
    {
        return [f = std::forward<F>(f), t = std::forward<T>(t)]
               (auto&&... args)
               { return f(t, std::forward<decltype(args)>(args)...); };
    }
    
    int main()
    {
        auto square = [](int x){ return x*x; };
    
        typedef std::vector<int> Row;
        Row row;
        Row squaredRow = Map(square, row);
    
        typedef std::vector<Row> Mat;
        Mat mat;
        auto squareRow = Map<Row, decltype(square)>;
        auto squareRowElems = Curry((Map<Row, decltype(square)>), square);
        Mat squaredMat = Map(squareRowElems, mat);
    }
    

    source: https://stackoverflow.com/a/33724222/1866775

    demo: http://ideone.com/16cx0l