шаблоны функций, частичное применение и вывод аргументов шаблона

Я пытаюсь получить следующую основную функцию для компиляции и работы, как и ожидалось:

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);
}

Прямо сейчас мой дополнительный код выглядит так:

#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... ); };
}

и он не компилируется.

Любая идея, как заставить компилятор вывести параметры шаблона?


person Tobias Hermann    schedule 14.11.2015    source источник
comment
Укажите ContainerOut для Map при вызове Map. например Map<vector<int>>, остальные параметры шаблона будут выведены компилятором.   -  person 0x6773    schedule 14.11.2015
comment
Или вы можете по умолчанию сделать его таким же, как ContainerIn, с небольшим жонглированием.   -  person Alan Stokes    schedule 14.11.2015
comment
@AlanStokes Даже принуждение ContainerOut к тому же, что и ContainerIn, только с использованием Container таким образом не помогает.   -  person Tobias Hermann    schedule 14.11.2015
comment
Я думаю, вы должны указать все параметры шаблона в auto squareElements = Curry(Map<Row>, square); для Map, потому что Curry попытается получить указатель на функцию в качестве первого аргумента. Но Map<Row> не является адресом какой-либо функции. Компилятор не сможет вывести другие параметры шаблона и, следовательно, тип Ret в Curry   -  person 0x6773    schedule 14.11.2015
comment
@mnciitbhu Вы имеете в виду как это? Это все еще не работает.   -  person Tobias Hermann    schedule 14.11.2015
comment
@TobiasHermann Взгляните на ideone.com/KQYVla   -  person 0x6773    schedule 14.11.2015


Ответы (2)


Ошибка компилятора говорит:

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

Измените функцию Curry на

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... ); };
}

или измените функцию Map на:

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

Это скомпилируется!

Взгляните на мой код: Ideone

person 0x6773    schedule 14.11.2015
comment
Это хорошо, но Map принимать xs по значению, а не по константной ссылке, на мой взгляд, слишком расточительно. Недостаточно переключиться на вашу версию Map или Curry. Нужно делать и то, и другое. Только изменение Curry вызывает ошибки. - person Tobias Hermann; 14.11.2015

Одно из возможных решений, позволяющее избежать использования std::placeholders::_1 с std::bind каждый раз.

#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);
}

источник: https://stackoverflow.com/a/33724222/1866775

демо: http://ideone.com/16cx0l

person Tobias Hermann    schedule 14.11.2015