Как насчет этого?
#include <cstdio>
#include <functional>
template <typename F, typename F_ret, typename... F_args,
typename G, typename G_ret, typename... G_args>
std::function<G_ret (F_args...)>
composer(F f, F_ret (F::*)(F_args...) const ,
G g, G_ret (G::*)(G_args...) const)
{
// Cannot create and return a lambda. So using std::function as a lambda holder.
std::function<G_ret (F_args...)> holder;
holder = [f, g](F_args... args) { return g(f(args...)); };
return holder;
}
template<typename F, typename G>
auto operator >> (F f, G g)
-> decltype(composer(f, &F::operator(), g, &G::operator()))
{
return composer(f, &F::operator(), g, &G::operator());
}
int main(void)
{
auto l1 = [](int i , int j) { return i + j; };
auto l2 = [](int a) { return a*a; };
printf("%d\n", (l1 >> l2 >> l2)(2, 3)); // prints 625
return 0;
}
Редактировать:
Вот некоторый расширенный код с поддержкой свободных указателей функций и указателей на функции-члены.У меня тоже есть тестовый код.Остерегайтесь количества вызовов виртуальных функций, происходящих при выполнении таких глубоко составленных объектов std :: function.Я думаю, что есть один виртуальный вызов функции для оператора () объекта std :: function.Вы также должны помнить о распределении и освобождении памяти.
#include <cstdio>
#include <functional>
template <typename F, typename F_ret, typename... F_args,
typename G, typename G_ret, typename... G_args>
std::function<G_ret (F_args...)>
composer(F f, F_ret (F::*)(F_args...) const ,
G g, G_ret (G::*)(G_args...) const)
{
// Cannot create and return a lambda. So using std::function as a lambda holder.
std::function<G_ret (F_args...)> holder;
holder = [f, g](F_args... args) { return g(f(args...)); };
return holder;
}
template<typename F_ret, typename... F_args>
std::function<F_ret (F_args...)>
make_function (F_ret (*f)(F_args...))
{
// Not sure why this helper isn't available out of the box.
return f;
}
template<typename F, typename F_ret, typename... F_args>
std::function<F_ret (F_args...)>
make_function (F_ret (F::*func)(F_args...), F & obj)
{
// Composing a member function pointer and an object.
// This one is probably doable without using a lambda.
std::function<F_ret (F_args...)> holder;
holder = [func, &obj](F_args... args) { return (obj.*func)(args...); };
return holder;
}
template<typename F, typename F_ret, typename... F_args>
std::function<F_ret (F_args...)>
make_function (F_ret (F::*func)(F_args...) const, F const & obj)
{
// Composing a const member function pointer and a const object.
// This one is probably doable without using a lambda.
std::function<F_ret (F_args...)> holder;
holder = [func, &obj](F_args... args) { return (obj.*func)(args...); };
return holder;
}
template<typename F, typename G>
auto operator >> (F f, G g)
-> decltype(composer(f, &F::operator(), g, &G::operator()))
{
return composer(f, &F::operator(), g, &G::operator());
}
// This one allows a free function pointer to be the second parameter
template<typename F, typename G_ret, typename... G_args>
auto operator >> (F f, G_ret (*g)(G_args...))
-> decltype(f >> make_function(g))
{
return f >> make_function(g);
}
// This one allows a free function pointer to be the first parameter
template<typename F, typename G_ret, typename... G_args>
auto operator >> (G_ret (*g)(G_args...), F f)
-> decltype(make_function(g) >> f)
{
return make_function(g) >> f;
}
// Not possible to have function pointers on both sides of the binary operator >>
int increment(int i) {
return i+1;
}
int sum(int i, int j) {
return i+j;
}
struct math {
int increment (int i) {
return i+1;
}
int sum (int i, int j) const {
return i+j;
}
};
int main(void)
{
auto l1 = [](int i , int j) { return i + j; };
auto l2 = [](int a) { return a*a; };
auto l3 = l1 >> l2 >> l2 >> increment; // does 11 allocs on Linux
printf("%d\n", l3(2, 3)); // prints 626
printf("%d\n", (sum >> l2)(3, 3)); // prints 36
math m;
printf("%d\n",
(make_function(&math::sum, m) >> make_function(&math::increment, m))(2, 3)); // prints 6
return 0;
}