首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >C++11中的递归lambda函数

C++11中的递归lambda函数
EN

Stack Overflow用户
提问于 2010-01-15 06:21:27
回答 10查看 100.9K关注 0票数 184

我是C++11的新手,我正在写下面的递归lambda函数,但是它不能编译。

sum.cpp

代码语言:javascript
复制
#include <iostream>
#include <functional>

auto term = [](int a)->int {
  return a*a;
};

auto next = [](int a)->int {
  return ++a;
};

auto sum = [term,next,&sum](int a, int b)mutable ->int {
  if(a>b)
    return 0;
  else
    return term(a) + sum(next(a),b);
};

int main(){
  std::cout<<sum(1,10)<<std::endl;
  return 0;
}

编译错误:

vimal@linux-718q:~/Study/09C++/c++0x/lambda> g++ -std=c++0x sum.cpp

sum.cpp:在lambda函数中: sum.cpp:18:36: error:‘((<lambda(int, int)>*)this)-><lambda(int, int)>::sum’不能用作函数

gcc版

gcc版本4.5.0 20091231 (实验版) (GCC)

但是,如果我像下面这样更改sum()的声明,它就会起作用:

代码语言:javascript
复制
std::function<int(int,int)> sum = [term,next,&sum](int a, int b)->int {
   if(a>b)
     return 0;
   else
     return term(a) + sum(next(a),b);
};

有没有人能帮我解释一下?

EN

回答 10

Stack Overflow用户

发布于 2016-11-30 02:56:19

有了C++14,现在只需几行代码就可以很容易地创建一个高效的递归lambda,而不必产生std::function的额外开销:

代码语言:javascript
复制
template <class F>
struct y_combinator {
    F f; // the lambda will be stored here
    
    // a forwarding operator():
    template <class... Args>
    decltype(auto) operator()(Args&&... args) const {
        // we pass ourselves to f, then the arguments.
        return f(*this, std::forward<Args>(args)...);
    }
};

// helper function that deduces the type of the lambda:
template <class F>
y_combinator<std::decay_t<F>> make_y_combinator(F&& f) {
    return {std::forward<F>(f)};
}

使用它,您的原始sum尝试将变成:

代码语言:javascript
复制
auto sum = make_y_combinator([term,next](auto sum, int a, int b) {
  if (a>b) {
    return 0;
  }
  else {
    return term(a) + sum(next(a),b);
  }
});

在C++17中,通过CTAD,我们可以添加一个扣减指南:

代码语言:javascript
复制
template <class F> y_combinator(F) -> y_combinator<F>;

这消除了对助手函数的需要。我们可以直接编写y_combinator{[](auto self, ...){...}}

在C++20中,使用CTAD进行聚合,就不需要演绎指南了。

票数 55
EN

Stack Overflow用户

发布于 2012-12-31 02:45:26

我有另一个解决方案,但只能使用无状态lambda:

代码语言:javascript
复制
void f()
{
    static int (*self)(int) = [](int i)->int { return i>0 ? self(i-1)*i : 1; };
    std::cout<<self(10);
}

这里的诀窍是lambdas可以访问静态变量,您可以将无状态变量转换为函数指针。

您可以将其与标准lambdas一起使用:

代码语言:javascript
复制
void g()
{
    int sum;
    auto rec = [&sum](int i) -> int
    {
        static int (*inner)(int&, int) = [](int& _sum, int i)->int 
        {
            _sum += i;
            return i>0 ? inner(_sum, i-1)*i : 1; 
        };
        return inner(sum, i);
    };
}

它在GCC 4.7中的工作

票数 26
EN

Stack Overflow用户

发布于 2017-08-23 02:41:55

要在不使用外部类和函数(如std::function或定点组合器)的情况下使lambda递归,可以在C++14 (live example)中使用以下结构:

代码语言:javascript
复制
#include <utility>
#include <list>
#include <memory>
#include <iostream>

int main()
{
    struct tree
    {
        int payload;
        std::list< tree > children = {}; // std::list of incomplete type is allowed
    };
    std::size_t indent = 0;
    // indication of result type here is essential
    const auto print = [&] (const auto & self, const tree & node) -> void
    {
        std::cout << std::string(indent, ' ') << node.payload << '\n';
        ++indent;
        for (const tree & t : node.children) {
            self(self, t);
        }
        --indent;
    };
    print(print, {1, {{2, {{8}}}, {3, {{5, {{7}}}, {6}}}, {4}}});
}

打印:

代码语言:javascript
复制
1
 2
  8
 3
  5
   7
  6
 4

注意,lambda的结果类型应该显式指定。

票数 23
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2067988

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档