[英]Can you capture a reference in a recursive lambda?
I've fully solved a particular problem on HackerRank ( https://www.hackerrank.com/challenges/ctci-recursive-staircase/problem ) using a recursive solution with memoization: 我已经使用带有备注的递归解决方案完全解决了HackerRank( https://www.hackerrank.com/challenges/ctci-recursive-staircase/problem )上的一个特定问题:
std::map<int, int> memoize;
int davis_staircase(int n) {
if (n == 0) {
return 1;
} else if (n < 0) {
return 0;
}
auto find = memoize.find(n);
if (find != memoize.end()) {
return find->second;
}
int num_steps = davis_staircase(n - 1) + davis_staircase(n - 2) + davis_staircase(n - 3);
memoize[n] = num_steps;
return num_steps;
}
I would like to hide the global std::map
(without using a class) that I'm using as the lookup and thought I'd try creating a lambda that I can call recursively and also capture the cache/map by reference. 我想隐藏用作查询的全局
std::map
(不使用类),并认为我会尝试创建可以递归调用的lambda并通过引用来捕获缓存/映射。 I've tried the following: 我尝试了以下方法:
int davis_staircase_2(int n) {
std::map<int, int> memo;
//auto recurse = [&memo](int n) -> int { // attempt (1)
//std::function<int(int)> recurse = [&memo](int n) -> int { // attempt (2)
std::function<int(std::map<int, int>&, int)> recurse = [](std::map<int, int>& memo, int n) -> int { // attempt (3)
if (n == 0) {
return 1;
} else if (n < 0) {
return 0;
}
auto find = memo.find(n);
if (find != memo.end()) {
return find->second;
}
//int num_steps = recurse(n - 1) + recurse(n - 2) + recurse(n - 3); // attempt (1) or (2)
int num_steps = recurse(memo, n - 1) + recurse(memo, n - 2) + recurse(memo, n - 3); // attempt (3)
memo[n] = num_steps;
return num_steps;
};
//return recurse(n); // attempt (1) or (2)
return recurse(memo, n); // attempt (3)
}
I have 3 slightly different attempts interleaved above but I cannot get any to compile. 我在上面交错了3次稍有不同的尝试,但是无法编译。 Is what I'm trying to do, possible?
我想做的是可能的吗?
I'm using clang on MacOS: 我在MacOS上使用clang:
Apple LLVM version 10.0.0 (clang-1000.10.44.4)
Target: x86_64-apple-darwin18.2.0
Thread model: posix
You forget to capture recurse
, so your code might be 您忘记捕获
recurse
,因此您的代码可能是
std::function<int(int)> recurse = [&recurse, &memo](int n) -> int { // attempt (2)
or 要么
std::function<int(int)> recurse = [&](int n) -> int { // attempt (2)
In the same way, for // attempt (3)
: 同样,对于
// attempt (3)
:
std::function<int(std::map<int, int>&, int)> recurse = [&recurse](std::map<int, int>& memo, int n) -> int { // attempt (3)
// attempt (1)
cannot be fixed as is, as type of recurse
is used before it is defined. // attempt (1)
无法按原样固定,因为在定义recurse
之前就使用了recurse
类型。
To do it without std::function
, you might use Y-combinator (require C++14, for generic lambda): 要在没有
std::function
情况下执行此操作,可以使用Y-combinator (对于通用lambda,需要C ++ 14):
int davis_staircase_2(int n) {
std::map<int, int> memo;
auto recurse = [&memo](auto self, int n) -> int { // attempt (4)
if (n == 0) {
return 1;
} else if (n < 0) {
return 0;
}
auto find = memo.find(n);
if (find != memo.end()) {
return find->second;
}
int num_steps = self(self, n - 1) + self(self, n - 2) + self(self, n - 3); // attempt (4)
memo[n] = num_steps;
return num_steps;
};
return recurse(recurse, n); // attempt (4)
}
You don't need a recursive function ... 您不需要递归函数...
int stepPerms(int n) {
std::map<int, int> memoize;
memoize[-2] = 0;
memoize[-1] = 0;
memoize[0] = 1;
for(int i=1;i<=n;++i)
{
memoize[i] = memoize[i - 1] + memoize[i - 2] + memoize[i-3];
}
return memoize[n];
}
You can do recursive lambda without type erasure (std::function). 您可以执行递归lambda,而无需类型擦除(std :: function)。 This is how it's done with generic lambdas:
这是使用通用lambda来完成的:
auto recurse = [](auto lambda) {
return [lambda](auto&&... args) {
return lambda(lambda, std::forward<decltype(args)>(args)...);
};
};
auto my_recursive_lambda = recurse([](auto self, std::map<int, int>& memo, int n) {
if (n == 0) {
return 1;
} else if (n < 0) {
return 0;
}
auto find = memo.find(n);
if (find != memo.end()) {
return find->second;
}
int num_steps = self(self, memo, n - 1) + self(self, memo, n - 2) + self(self, memo, n - 3);
memo[n] = num_steps;
return num_steps;
});
my_recursive_lambda(memo, n); // magic!
If you really need this for c++11, you will need std::function
: 如果您确实需要c ++ 11,则需要
std::function
:
auto recurse = std::function<int(std::map<int, int>&, int)>{};
recurse = [&recurse](std::map<int, int>& memo, int n) {
// same as you tried.
}
Or if you give up convenience, you can hand roll your lambda type: 或者,如果您放弃方便,则可以手动滚动lambda类型:
struct {
auto operator()(std::map<int, int>& memo, int n) -> int {
auto&& recurse = *this;
if (n == 0) {
return 1;
} else if (n < 0) {
return 0;
}
auto find = memo.find(n);
if (find != memo.end()) {
return find->second;
}
//int num_steps = recurse(n - 1) + recurse(n - 2) + recurse(n - 3); // attempt (1) or (2)
int num_steps = recurse(memo, n - 1) + recurse(memo, n - 2) + recurse(memo, n - 3); // attempt (3)
memo[n] = num_steps;
return num_steps;
}
} recurse{};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.