2

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?

Tobias Hermann
  • 9,936
  • 6
  • 61
  • 134
  • 1
    Specify `ContainerOut` for `Map`, when calling `Map`. e.g. `Map>`, other template parameters will be deduced by compiler. – 0x6773 Nov 14 '15 at 08:54
  • Or you could default it to be the same as `ContainerIn`, with a little juggling. – Alan Stokes Nov 14 '15 at 09:00
  • @AlanStokes Even forcing `ContainerOut` to be the same as `ContainerIn` by only using `Container` [like this](http://ideone.com/IENKSe) does not help. – Tobias Hermann Nov 14 '15 at 09:07
  • I think you must specify all template parameters at `auto squareElements = Curry(Map, square);` for `Map` because `Curry` will try to get pointer to a function as first argument. But `Map` is not the address of any function. Compiler will fail to deduce the other template parameters and hence the `Ret` type in `Curry` – 0x6773 Nov 14 '15 at 09:16
  • @mnciitbhu You mean like [this](http://ideone.com/rzvX7b)? It still does not work. – Tobias Hermann Nov 14 '15 at 09:33
  • @TobiasHermann Have a look at http://ideone.com/KQYVla – 0x6773 Nov 14 '15 at 09:58

2 Answers2

0

Compiler error says :

deduced conflicting types for parameter 'Arg1' ('const main()::<lambda(int)>&' and 'main()::<lambda(int)>')
 auto squareElements = Curry(Map<Row, decltype(square)>, square);
                                                               ^

Change the function Curry to

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

or change function Map to :

template <typename Container, typename F>
Container Map(F f, Container xs );

This will compile!

Have a Look at my code : Ideone

0x6773
  • 1,116
  • 1
  • 14
  • 33
  • That is nice, but `Map` taking `xs` by value and not by const ref any more is a bit too wasteful in my opinion. It is not enough to switch to your version of `Map` ***or*** `Curry`. One has to do both. Only changing `Curry` [produces errors](http://ideone.com/HYqYll). – Tobias Hermann Nov 14 '15 at 11:35
0

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

Community
  • 1
  • 1
Tobias Hermann
  • 9,936
  • 6
  • 61
  • 134