Функтор чтения в C ++ - PullRequest
       67

Функтор чтения в C ++

0 голосов
/ 12 марта 2020

Я пытаюсь реализовать функтор читателя в C ++. Haskell соответствует определению fmap :: (a -> b) -> (r -> a) -> (r -> b)

Моя версия на C ++:

template<class A, class B, class R>
B fmap(const std::function<B(A)> &funcA, const std::function<A(R)> &funcR) {
    return funcA(funcR());
}

std::string function_1(int n);
double function_2(std::string s);

fmap(function_2, function_1);

Ошибка:

note: candidate template ignored: could not match 'function<type-parameter-0-1 (type-parameter-0-0)>' against 'double (std::__1::basic_string<char>)'

B fmap(const std::function<B(A)> &funcA, const std::function<A(R)> &funcR) {

Как правильно реализовать функцию fmap?

Ответы [ 2 ]

2 голосов
/ 12 марта 2020

Вы можете сделать это с помощью простого трюка преобразования шаблона из Вывод типа шаблона с помощью std :: function

#include <functional>
#include <iostream>
#include <string>
using namespace std;

template<class T>
struct AsFunction
    : public AsFunction<decltype(&T::operator())>
{};

template<class ReturnType, class... Args>
struct AsFunction<ReturnType(Args...)> {
    using type = std::function<ReturnType(Args...)>;
};

template<class ReturnType, class... Args>
struct AsFunction<ReturnType(*)(Args...)> {
    using type = std::function<ReturnType(Args...)>;
};


template<class Class, class ReturnType, class... Args>
struct AsFunction<ReturnType(Class::*)(Args...) const> {
    using type = std::function<ReturnType(Args...)>;
};

template<class F>
auto toFunction(F f) -> typename AsFunction<F>::type {
    return { f };
}

template<class A, class B, class R>
B fmap(const std::function<B(A)>& funcA, const std::function<A(R)>& funcR, R value) {
    return funcA(funcR(value));
}

template <class T>
auto ToFunction(T t) {
    return t;
}

std::string function_1(int n) {
    return ""s;
}

double function_2(std::string s) {
    return 0.0;
}

int main() {
    fmap(toFunction(function_2), toFunction(function_1), 5);
    return 0;
}
1 голос
/ 12 марта 2020

Проблема в том, что вывод шаблона работает с точным соответствием по типу, без преобразований.

Вы передаете указатели на функции, которые отличаются от типа std::function, поэтому вывод параметров шаблона будет fail.

Правильный способ - использовать вызываемые элементы в качестве аргументов шаблона. Это гарантирует, что вычет будет работать. Часто вам не нужно проверять сигнатуру вызываемого объекта, поскольку, если он используется в функции, вы получите ошибку времени компиляции, если он используется неправильно.

Если вы все еще хотите проверьте подпись, это не очень сложно сделать с чертой типа.

#include <string>

template<class A, class B>
B fmap(A a, B b) {
    return a(b(std::string{}));
}

std::string function_1(int n);
double function_2(std::string s);

fmap(function_2, function_1);
...