Ste*_*uer 2 c++ lambda y-combinator c++17
我正在尝试构建一个具有递归能力的 lambda 自作用域的干净整洁的实现(这基本上是一个 Y 组合器,尽管我认为技术上不完全)。这是一个旅程,它带我到许多其他人中,这个线程,这个线程和这个线程。
我已经尽可能干净地归结了我的问题之一:如何传递以 lambda 作为模板参数的模板化函子?
#include <string>
#include <iostream>
#define uint unsigned int
template <class F>
class Functor {
public:
F m_f;
template <class... Args>
decltype(auto) operator()(Args&&... args) {
return m_f(*this, std::forward<Args>(args)...);
}
};
template <class F> Functor(F)->Functor<F>;
class B {
private:
uint m_val;
public:
B(uint val) : m_val(val) {}
uint evaluate(Functor<decltype([](auto & self, uint val)->uint {})> func) const {
return func(m_val);
}
};
int main() {
B b = B(5u);
Functor f = Functor{[](auto& self, uint val) -> uint {
return ((2u * val) + 1u);
}};
std::cout << "f applied to b is " << b.evaluate(f) << "." << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码不起作用,Visual Studio 声称f(在b.evaluate(f)调用中)与参数类型不匹配。
我的假设是auto & self不够聪明,无法完成这项工作。我该如何解决这个问题?当这些东西本质上无法定义时,我如何存储和传递它们?这就是为什么我见过的许多 Y-combinator 实现都有奇怪的双重包裹的东西吗?
任何帮助或解释将不胜感激。
我看到的唯一方法是创建evaluate()一个模板方法;如果你想确保收到一个Functor(但你可以简单地接受一个可调用的:见Yakk 的回答):
template <typename F>
uint evaluate(Functor<F> func) const {
return func(m_val);
}
Run Code Online (Sandbox Code Playgroud)
考虑到每个 lambda 都是不同的类型,因为您可以使用以下简单代码进行验证
auto l1 = []{};
auto l2 = []{};
static_assert( not std::is_same_v<decltype(l1), decltype(l2)> );
Run Code Online (Sandbox Code Playgroud)
因此强加特定的 lambda 类型evaluate()无法工作,因为如果您使用(显然)相同的 lambda 函数调用该方法,则调用不匹配,如下面的示例所示
auto l1 = []{};
auto l2 = []{};
void foo (decltype(l1))
{ }
int main ()
{
foo(l2); // compilation error: no matching function for call to 'foo'
}
Run Code Online (Sandbox Code Playgroud)