置顶

一个求和方法:

1
2
3
std::function<int(const int&)>s = [&](const int& n) {
return n == 1 ? 1 : n + s(n - 1);
};

可以直接使用

0x00问题引入

对于一个求自然数1-N和的问题,我们很容易写出以下递归公式:

1
f(n) = n == 1 ? 1 : n + f(n - 1);

若想使用C++lambda表达式实现上述过程,我们很容易将其改写为以下代码:

1
2
3
const auto& f = [](const int& n) {
return n == 1 ? 1 : n + f(n - 1);
};

发现编译无法通过,为什么呢?原因是,由于lambda表达式的匿名特性,无法直接在lambda内部递归调用lambda,我们需要另寻其道来解决该问题。

0x01使用std::function

std::function可以把lambda包装起来,相当于赋予了其一个函数名,在通过引用捕获并实现递归调用,实现如下:

1
2
3
4
5
6
7
const auto& sum1 = [](const int& n) {
std::function<int(const int&)>s;
s = [&](const int& n) {
return n == 1 ? 1 : n + s(n - 1);
};
return s(n);
};

0x02将lambda作为参数

先附上代码:

1
2
3
4
5
6
const auto& sum2 = [](const int& n) {
const auto& s = [&](auto&& self, const int& x) -> int{
return x == 1 ? 1 : x + self(self, x - 1);
};
return s(s,n);
};

注意到,调用s(s,n)时,我们把lambda表达式本身作为了参数传入来实现递归调用。

error: auto not alowed in lambda prameter

0x03使用Y组合子

构造一个Y组合子如下:

1
2
3
4
5
6
7
8
9
const auto& y = [](const auto& f) {
return [&](const auto& x) {
return x(x);
}([&](const auto& x) -> std::function<int(int)> {
return f([&](const int& n) {
return x(x)(n);
});
});
};

再实现一个求和函数的高阶函数如下:

1
2
3
4
5
const auto& sum3 = [](const auto& f) {
return [=](const int& n) {
return n == 1 ? 1 : n + f(n - 1);
};
};

然后连接即可。

0x04测试

在main中简单测试一下上述实现:

1
2
3
4
5
int main() {
std::cout << sum1(100);//print 5050
std::cout << sum2(100);//print 5050
std::cout << y(sum3)(100);//print 5050
}

运行结果符合预期。

参考来源:https://blog.csdn.net/weixin_43686836/article/details/106952856