首先,我将编写一个糟糕的、功能性的 Y 组合器。
using fib_f = std::function<int(int)>;
using protofib_f = std::function< int( fib_f, int ) >;
int protofib( std::function<int(int)> f, int n) {
if (n>1) return f(n-1)+f(n-1);
return n;
}
auto Y( protofib_f f )->fib_f {
return [=](int n) { return f( Y(f), n ); };
}
丑陋,但它的工作原理。
我们可以编写一个更好的 Y 组合器。
template<class R>
auto Y = [&](auto&& f){
return [=](auto&&...args)->R {
return f( Y<R>(f), decltype(args)(args)... );
};
};
简单地说,它确实需要指定其返回类型。
auto fib = Y<int>(protofib);
它还推迟了类型擦除,从而提高了性能。
我们可以从 protofib 中剥离类型擦除:
auto protofib = [](auto&& f, int n)->int {
if (n>1) return f(n-1)+f(n-1);
return n;
};
通过把它变成一个lambda。
改进的 Y 组合器需要更多样板,因为 lambdas 无法访问:
template<class F>
struct y_combinate_t {
F f;
template<class...Args>
decltype(auto) operator()(Args&&...args)const {
return f(*this, std::forward<Args>(args)...);
}
};
template<class F>
y_combinate_t<std::decay_t<F>> y_combinate( F&& f ) {
return {std::forward<F>(f)};
};
再次,零类型擦除开销,并且这个不需要显式传递返回类型。(从我这里偷来的)。
在c++17中,y_combinate
可以消除助手:
template<class F>
struct y_combinate {
F f;
template<class...Args>
decltype(auto) operator()(Args&&...args)const {
return f(*this, std::forward<Args>(args)...);
}
};
template<class F>
y_combinate(F&& f)->y_combinate<std::decay_t<F>>;
有扣除指南。
y_combinate{ protofib }
是一个完整的斐波那契函数。
活生生的例子。
更进一步,您可以将记忆添加到您的 y 组合器中。