Possible Duplicate:
Recursive lambda functions in c++0x
Why can't I call a lambda recursively if I write it as:
auto a = [&]
{
static int i = 0; i++;
std::cout << i << std::endl;
if (i<10)
a(); //recursive call
};
It gives compilation error (ideone):
prog.cpp:8:18: error: '((const main()::<lambda()>*)this)->main()::<lambda()>::a' cannot be used as a function
prog.cpp: In function 'int main()':
prog.cpp:9:9: error: variable 'auto a' with 'auto' type used in its own initializer
What does the error mean?
I understand the reason why I can't write this:
auto i=i+1; //error: unable to deduce 'auto' from '<expression error>'
We can't write this because the type of i
has to be deduced from it's initialization, which means the type cannot be deduced if i
itself appears in the initialization (ideone). But how does it matter in case of lambda? If I'm not wrong, the type of a lambda is determined by it's parameter(s) and the return type; it doesn't depend on the body if it returns nothing (in which case, the return type is deduced as void
, irrespective of other statements in the lambda-body).
Anyway, I got a workaround, and I can use std::function
instead as:
std::function<void()> a = [&]
{
static int i = 0; i++;
std::cout << i << std::endl;
if (i<10)
a();
};
which compile fines (ideone). But I'm still interested to know the reason why the auto
version doesn't compile.
The reason is that there is no special case for lambda-expression initializers of auto
variables.
Such special cases would be prone to errors and misuses. You need to define the rules when you propose that something like a()
should work. How is the operator()
looked up? What is the precise state of a
's type? Will the type be complete? (which implies that you already know the capture list of the lambda). Once you have formulated that in a format reasonable for a spec, it would be easier to make statements on it.
Allowing your use case would mean yet another case where you need to scan ahead in code, because to determine the type of a
in a()
you must be sure that the initializer ends with nothing that could "unlambda" the type
struct y { void operator()() { } };
template<typename T> y operator+(T, y) { return y(); }
auto x = [] { x(); } + y();
In this case, x()
would call y::operator()
, not the lambda.
As it is now, a
is simply forbidden to be mentioned in its entire initializer. Because in C++, auto
is not a type. It is merely a type specifier standing for a to-be-deduced type. As a consequence, an expression can never have type auto.
As I see it the important difference between the auto a
case and the std::function<void()> a
case is that the type std::function<void()>
doesn't know/care about what the type of the real function it refers to really is. Writing:
std::function<void()> a;
is perfectly fine, where as:
auto a;
makes little sense. So when the time comes to synthesize the capture if you use std::function<void()>
all that needs to be known about the type is already known, whereas with auto
it's not yet known.
In a recursive function f
is defined by f
and return type of f
is also determined by f
in case of auto
so it leads to infinite recursion.
when auto
tries to derive a type. decltype(f()) will further deduce to another decltype(f)` as f derives to f e.g. a call on anything recursive is recursive too. return type determination turns recursive when applied on a recursive function. in a recursive function end of the recursion may be done on runtime. but determination is static only
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With