Search code examples
c++c++11recursionlambda

How to make a recursive lambda


I am writing the following recursive lambda function:

#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;
}

...but it doesn't compile:

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

sum.cpp: In lambda function:
sum.cpp:18:36: error: ‘`((<lambda(int, int)>*)this)-><lambda(int, int)>::sum`’ cannot be used as a function

But if I change the declaration of sum() as below, it works:

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);
};

Could someone throw light on this?

gcc version 4.5.0 20091231 (experimental) (GCC)


Solution

  • Think about the difference between the auto version and the fully specified type version. The auto keyword infers its type from whatever it's initialized with, but what you're initializing it with needs to know what its type is (in this case, the lambda closure needs to know the types it's capturing). Something of a chicken-and-egg problem.

    On the other hand, a fully specified function object's type doesn't need to "know" anything about what is being assigned to it, and so the lambda's closure can likewise be fully informed about the types its capturing.

    Consider this slight modification of your code and it may make more sense:

    std::function<int(int, int)> sum;
    
    sum = [term, next, &sum](int a, int b) -> int {
        if (a > b)
            return 0;
        else
            return term(a) + sum(next(a), b);
    };
    

    Obviously, this wouldn't work with auto. Recursive lambda functions work perfectly well (at least they do in MSVC, where I have experience with them), it's just that they aren't really compatible with type inference.