weima weima - 10 days ago 5
C++ Question

Recursive lambda functions in C++11

I am new to C++11. I am writing the following recursive lambda function, but it doesn't compile.

sum.cpp



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


compilation error:



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

gcc version



gcc version 4.5.0 20091231 (experimental) (GCC)

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 please throw light on this?

Answer

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.