Conversion of lambda expression to function pointer - c++

This is a follow up question to this question: Lambda how can I pass as a parameter
MSDN supposedly has marked the item as fixed. I took a look at the specifications, but I'm having trouble converting their specifications into what the syntax should be.
So for example:
void printOut(int(*eval)(int))
{
for(int x = 0; x < 4; ++x)
{
std::cout << eval(x) << std::endl;
}
}
Now say I have the lambda:
auto lambda1 = [](int x)->int{return x;};
What is the syntax to convert lambda1 into the functional pointer equivalent so it can be passed to printOut?
Also, what about lambdas which actually have something in the brackets? For example:
int y = 5;
auto lambda2 = [y](void)->int{return y;};
If this kind of lambda can't be converted to a function pointer, is there an alternative method for passing this type of lambda expression to printOut (or even a modified version of printOut, if so what's the syntax)?

There is no syntax per se, it's an implicit conversion. Simply cast it (explicitly or implicitly) and you'll get your function pointer. However, this was fixed after Visual Studio 2010 was released, so is not present.†
You cannot make a capture-full lambda into a function pointer ever, as you noted, so it's the function printOut that'll have to change. You can either generalize the function itself:
// anything callable
template <typename Func>
void printOut(Func eval)
{
// ...
}
Or generalize the function type in particular:
// any function-like thing that fits the int(int) requirement
void printOut(std::function<int(int)> eval)
{
// ...
}
Each has their own trade-off.
†As far as I know, it's unknown of we'll get it in a service pack, or if we need to wait until a new release.

Related

Name the type of a template function in C++ [duplicate]

It is necessary for me to use std::function but I don't know what the following syntax means.
std::function<void()> f_name = []() { FNAME(); };
What is the goal of using std::function? Is it to make a pointer to a function?
std::function is a type erasure object. That means it erases the details of how some operations happen, and provides a uniform run time interface to them. For std::function, the primary1 operations are copy/move, destruction, and 'invocation' with operator() -- the 'function like call operator'.
In less abstruse English, it means that std::function can contain almost any object that acts like a function pointer in how you call it.
The signature it supports goes inside the angle brackets: std::function<void()> takes zero arguments and returns nothing. std::function< double( int, int ) > takes two int arguments and returns double. In general, std::function supports storing any function-like object whose arguments can be converted-from its argument list, and whose return value can be converted-to its return value.
It is important to know that std::function and lambdas are different, if compatible, beasts.
The next part of the line is a lambda. This is new syntax in C++11 to add the ability to write simple function-like objects -- objects that can be invoked with (). Such objects can be type erased and stored in a std::function at the cost of some run time overhead.
[](){ code } in particular is a really simple lambda. It corresponds to this:
struct some_anonymous_type {
some_anonymous_type() {}
void operator()const{
code
}
};
an instance of the above simple pseudo-function type. An actual class like the above is "invented" by the compiler, with an implementation defined unique name (often including symbols that no user-defined type can contain) (I do not know if it is possible that you can follow the standard without inventing such a class, but every compiler I know of actually creates the class).
The full lambda syntax looks like:
[ capture_list ]( argument_list )
-> return_type optional_mutable
{
code
}
But many parts can be omitted or left empty. The capture_list corresponds to both the constructor of the resulting anonymous type and its member variables, the argument_list the arguments of the operator(), and the return type the return type. The constructor of the lambda instance is also magically called when the instance is created with the capture_list.
[ capture_list ]( argument_list ) -> return_type { code }
basically becomes
struct some_anonymous_type {
// capture_list turned into member variables
some_anonymous_type( /* capture_list turned into arguments */ ):
/* member variables initialized */
{}
return_type operator()( argument_list ) const {
code
}
};
Note that in c++20 template arguments were added to lambdas, and that isn't covered above.
[]<typename T>( std::vector<T> const& v ) { return v.size(); }
1 In addition, RTTI is stored (typeid), and the cast-back-to-original-type operation is included.
Let's break the line apart:
std::function
This is a declaration for a function taking no parameters, and returning no value. If the function returned an int, it would look like this:
std::function<int()>
Likewise, if it took an int parameter as well:
std::function<int(int)>
I suspect your main confusion is the next part.
[]() { FNAME(); };
The [] part is called a capture clause. Here you put variables that are local to the declaration of your lambda, and that you want to be available within the lambda function itself. This is saying "I don't want anything to be captured". If this was within a class definition and you wanted the class to be available to the lambda, you might do:
[this]() { FNAME(); };
The next part, is the parameters being passed to the lambda, exactly the same as if it was a regular function. As mentioned earlier, std::function<void()> is a signature pointing to a method that takes no parameters, so this is empty also.
The rest of it is the body of the lambda itself, as if it was a regular function, which we can see just calls the function FNAME.
Another Example
Let's say you had the following signature, that is for something that can sum two numbers.
std::function<int(int, int)> sumFunc;
We could now declare a lambda thusly:
sumFunc = [](int a, int b) { return a + b; };
Not sure if you're using MSVC, but here's a link anyway to the lamda expression syntax:
http://msdn.microsoft.com/en-us/library/dd293603.aspx
Lambdas with captures (stateful lambdas) cannot be assigned to each other since they have unique types, even if they look exactly the same.
To be able to store and pass around lambdas with captures, we can use "std::function" to hold a function object constructed by a lambda expression.
Basically "std::function" is, to be able to assign lambda functions with different content structures to a lambda function object.
Exp :
auto func = [](int a){
cout << "a:" << a << endl;
};
func(40);
//
int x = 10;
func = [x](int a){ //ATTENTION(ERROR!): assigning a new structure to the same object
cout << "x:" << x << ",a:" << a << endl;
};
func(2);
So the above usage will be incorrect.
But if we define a function object with "std::function":
auto func = std::function<void(int)>{};
func = [](int a){
cout << "a:" << a << endl;
};
func(40);
//
int x = 10;
func = [x](int a){ //CORRECT. because of std::function
//...
};
int y = 11;
func = [x,y](int a){ //CORRECT
//...
};

Can lambdas translate into functions?

Common knowledge dictated that lambda functions are functors under the hood.
In this video (# about 45:43) Bjarne says:
I mentioned that a lambda translates into a function object, or into a function if that's convenient
I can see how this is a compiler optimization (ie it doesn't change the perception of lambdas as unnamed functors which means that eg lambdas still won't overload) but are there any rules that specify when this is applicable?
Edit
The way I understand the term translate (and that's what I'm asking about) has nothing to do with conversion (I'm not asking whether lambdas are convertible to function ptr etc). By translate I mean "compile lambda expressions into functions instead of function objects".
As mentioned in cppreference :
The lambda expression constructs an unnamed prvalue temporary object of unique unnamed non-union non-aggregate type, known as closure type.
The question is : can this object be ommited and have a plain function instead? If yes, then when and how?
Note: I imagine one such rule being "don't capture anything" but I can't find any reliable sources to confirm it
TLDR: if you only use lambda to convert it to a function pointer (and only invoke it via that function pointer), it is always profitable to omit the closure object. Optimizations which enable this are inlining and dead code elimination. If you do use the lambda itself, it is still possible to optimize the closure away, but requires somewhat more aggressive interprocedural optimization.
I will now try to show how that works under the hood. I will use GCC in my examples, because I'm more familiar with it. Other compilers should do something similar.
Consider this code:
#include <stdio.h>
typedef int (* fnptr_t)(int);
void use_fnptr(fnptr_t fn)
{
printf("fn=%p, fn(1)=%d\n", fn, fn(1));
}
int main()
{
auto lam = [] (int x) { return x + 1; };
use_fnptr((fnptr_t)lam);
}
Now, I compile it and dump intermediate representation (for versions prior to 6, you should add -std=c++11):
g++ test.cc -fdump-tree-ssa
A little cleaned-up and edited (for brevity) dump looks like this:
// _ZZ4mainENKUliE_clEi
main()::<lambda(int)> (const struct __lambda0 * const __closure, int x)
{
return x_1(D) + 1;
}
// _ZZ4mainENUliE_4_FUNEi
static int main()::<lambda(int)>::_FUN(int) (int D.2780)
{
return main()::<lambda(int)>::operator() (0B, _2(D));
}
// _ZZ4mainENKUliE_cvPFiiEEv
main()::<lambda(int)>::operator int (*)(int)() const (const struct __lambda0 * const this)
{
return _FUN;
}
int main() ()
{
struct __lambda0 lam;
int (*<T5c1>) (int) _3;
_3 = main()::<lambda(int)>::operator int (*)(int) (&lam);
use_fnptr (_3);
}
That is, lambda has 2 member functions: function call operator and a conversion operator and one static member function _FUN, which simply invokes lambda with this set to zero. main calls the conversion operator and passes the result to use_fnptr - exactly as it is written in the source code.
I can write:
extern "C" int _ZZ4mainENKUliE_clEi(void *, int);
int main()
{
auto lam = [] (int x) { return x + 1; };
use_fnptr((fnptr_t)lam);
printf("%d %d %d\n", lam(10), _ZZ4mainENKUliE_clEi(&lam, 11), __lambda0::_FUN(12));
printf("%p %p\n", &__lambda0::_FUN, (fnptr_t)lam);
return 0;
}
This program outputs:
fn=0x4005fc, fn(1)=2
11 12 13
0x4005fc 0x4005fc
Now, I think it's pretty obvious, that the compiler should inline lambda (_ZZ4mainENKUliE_clEi) into _FUN (_ZZ4mainENUliE_4_FUNEi), because _FUN is the only caller. And inline operator int (*)(int) into main (because this operator simply returns a constant). GCC does exactly this, when compiling with optimization (-O). You can check this like:
g++ test.cc -O -fdump-tree-einline
Dump file:
// Considering inline candidate main()::<lambda(int)>.
// Inlining main()::<lambda(int)> into static int main():<lambda(int)>::_FUN(int).
static int main()::<lambda(int)>::_FUN(int) (int D.2822)
{
return _2(D) + 1;
}
The closure object is gone. Now, a more complicated case, when lambda itself is used (not a function pointer). Consider:
#include <stdio.h>
#define PRINT(x) printf("%d", (x))
#define PRINT1(x) PRINT(x); PRINT(x); PRINT(x); PRINT(x);
#define PRINT2(x) do { PRINT1(x) PRINT1(x) PRINT1(x) PRINT1(x) } while(0)
__attribute__((noinline)) void use_lambda(auto t)
{
t(1);
}
int main()
{
auto lam = [] (int x) { PRINT2(x); };
use_lambda(lam);
return 0;
}
GCC will not inline lambda, because it is rather huge (that is what I used printf's for):
g++ test2.cc -O2 -fdump-ipa-inline -fdump-tree-einline -fdump-tree-esra
Early inliner's dump:
Considering inline candidate main()::<lambda(int)>
will not early inline: void use_lambda(auto:1) [with auto:1 = main()::<lambda(int)>]/16->main()::<lambda(int)>/19, growth 46 exceeds --param early-inlining-insns
But "early interprocedural scalar replacement of aggregates" pass will do what we want:
;; Function main()::<lambda(int)> (_ZZ4mainENKUliE_clEi, funcdef_no=14, decl_uid=2815, cgraph_uid=12, symbol_order=12)
IPA param adjustments: 0. base_index: 0 - __closure, base: __closure, remove_param
1. base_index: 1 - x, base: x, copy_param
The first parameter (i.e., closure) is not used, and it gets removed. Unfortunately interprocedural SRA is not able to optimize away indirection, which is introduced for captured values (though there are cases when it would be obviously profitable), so there is still some room for enhancements.
From Lambda expressions §5.1.2 p6 (draft N4140)
The closure type for a non-generic lambda-expression with no lambda-capture has a public non-virtual non-
explicit const conversion function to pointer to function with C ++ language linkage having the same
parameter and return types as the closure type’s function call operator.
The standard quote has already been posted, I want to add some examples.
You can assign lambdas to function pointers as long as there are no captured variables:
Legal:
int (*f)(int) = [] (int x) { return x + 1; }; // assign lambda to function pointer
int z = f(3); // use the function pointer
Illegal:
int y = 5;
int (*g)(int) = [y] (int x) { return x + y; }; // error
Legal:
int y = 5;
int z = ([y] (int x) { return x + y; })(2); // use lambda directly
(Edit)
Since we can not ask Bjarne what he meant exactly, I want to try a few interpretations.
"translate" meaning "convert"
This is what I understood initially, but it is clear now that the question is not about this possible meaning.
"translate" as used in the C++ standard, meaning "compile" (more or less)
As Sebastian Redl already commented, there are no function objects on the binary level. There is just opcodes and data, and the standard does not talk about, or specify, any binary formats.
"translate" meaning "being semantically equivalent"
This would imply that if A and B are semantically equivalent, the produced binary code for A and B could be the same. The rest of my answer uses this interpretation.
A closure consists of two parts:
the statements in the lambda body, "code"
the captured variable values or references, "data"
This is equivalent to a functor, as already stated in the question.
Functors can be seen as a subset of objects, because they have code and data, but only one member function: the call operator. So closures could be seen as semantically equivalent to a restricted form of objects.
A function on the other hand, has no data associated with it. There are the arguments of course, but these must be supplied by the caller and can change from one invocation to the other. This is a semantic difference to a closure, where the bound variables can not be changed and are not supplied by the caller.
A member function is not something independent, as it can not work without its object, so I think the question refers to a freestanding function.
So no, a lambda is in general not semantically equivalent to a function.
There is the obvious special case of a lambda with no captured variables, where the functor consists only of the code, and this is equivalent to a function.
But, a lambda could be said to be semantically equivalent to a set of functions. Each possible closure (distinct combination of values/references for the bound variables) would be equivalent to one function in that set.
Of course this can only be useful when the bound variables can only have a very limited set of values / are references to only a few different variables, if at all.
For example I see no reason why a compiler could not treat the following two snippets as (almost*) equivalent:
void Test(bool cond, int x)
{
int y;
if(cond) y = 5;
else y = 3;
auto f = [y](int x) { return x + y; };
// more code that
// uses f
}
A clever compiler could see that y can only have the values 5 or 3, and compile as if it would be written like this:
int F1(int x)
{
return x + 5;
}
int F2(int x)
{
return x + 3;
}
void Test(bool cond, int x)
{
int (*f)(int);
if(cond) f = F1;
else f = F2;
// more code that
// uses f
}
(*) Of course it depends on what more code that uses f does exactly.
Another (maybe better) example would be a lambda that always binds the same variable by reference. Then, there is only one possible closure, and so it is equivalent to a function, if the function has access to that variable by other means than by passing it as an argument.
Another observation that might be helpful is that asking
can this object [closure] be ommited and have a plain function instead? If yes,
then when and how?
is more or less the same as asking when and how a member function can be used without the object. Since lambdas are functors, and functors are objects, the two questions are closely related.
The bound variables of the lambda correspond to the data members of the object, and the lambda body corresponds to the body of the member function.
To give another kind of insight, let have a look to the code produced by clang when compiling the following snippet:
int (*f) = []() { return 0; }
If you compile this with:
clang++ -std=c++11 -S -o- -emit-llvm a.cc
You get the following LLVM bytecode for the lambda definition:
define internal i32 #"_ZNK3$_0clEv"(%class.anon* %this) #0 align 2 {
%1 = alloca %class.anon*, align 8
store %class.anon* %this, %class.anon** %1, align 8
%2 = load %class.anon** %1
ret i32 0
}
define internal i32 #"_ZN3$_08__invokeEv"() #1 align 2 {
%1 = call i32 #"_ZNK3$_0clEv"(%class.anon* undef)
ret i32 %1
}
The first function takes an instance of %class.anon* and return 0: that's the call operator. The second creates an instance of this class (undef) and then call its call operator and return the value.
When compiled with -O2, the whole lambda is turned into:
define internal i32 #"_ZN3$_08__invokeEv"() #0 align 2 {
ret i32 0
}
So that's a single function that returns 0.
I mentioned that a lambda translates into a function object, or into a function if that's convenient
That's exactly what clang does! It transforms the lambda into a function object, and when possible optimize it to a function.
No, it can't be done. Lambdas are defined to be functors, and I don't see the as-if rule helping here.
[C++14: 5.1.2/6]: The closure type for a non-generic lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function with C++ language linkage (7.5) having the same parameter and return types as the closure type’s function call operator. [..]
…followed by similar wording for generic lambdas.

What is the purpose of std::function and how to use it?

It is necessary for me to use std::function but I don't know what the following syntax means.
std::function<void()> f_name = []() { FNAME(); };
What is the goal of using std::function? Is it to make a pointer to a function?
std::function is a type erasure object. That means it erases the details of how some operations happen, and provides a uniform run time interface to them. For std::function, the primary1 operations are copy/move, destruction, and 'invocation' with operator() -- the 'function like call operator'.
In less abstruse English, it means that std::function can contain almost any object that acts like a function pointer in how you call it.
The signature it supports goes inside the angle brackets: std::function<void()> takes zero arguments and returns nothing. std::function< double( int, int ) > takes two int arguments and returns double. In general, std::function supports storing any function-like object whose arguments can be converted-from its argument list, and whose return value can be converted-to its return value.
It is important to know that std::function and lambdas are different, if compatible, beasts.
The next part of the line is a lambda. This is new syntax in C++11 to add the ability to write simple function-like objects -- objects that can be invoked with (). Such objects can be type erased and stored in a std::function at the cost of some run time overhead.
[](){ code } in particular is a really simple lambda. It corresponds to this:
struct some_anonymous_type {
some_anonymous_type() {}
void operator()const{
code
}
};
an instance of the above simple pseudo-function type. An actual class like the above is "invented" by the compiler, with an implementation defined unique name (often including symbols that no user-defined type can contain) (I do not know if it is possible that you can follow the standard without inventing such a class, but every compiler I know of actually creates the class).
The full lambda syntax looks like:
[ capture_list ]( argument_list )
-> return_type optional_mutable
{
code
}
But many parts can be omitted or left empty. The capture_list corresponds to both the constructor of the resulting anonymous type and its member variables, the argument_list the arguments of the operator(), and the return type the return type. The constructor of the lambda instance is also magically called when the instance is created with the capture_list.
[ capture_list ]( argument_list ) -> return_type { code }
basically becomes
struct some_anonymous_type {
// capture_list turned into member variables
some_anonymous_type( /* capture_list turned into arguments */ ):
/* member variables initialized */
{}
return_type operator()( argument_list ) const {
code
}
};
Note that in c++20 template arguments were added to lambdas, and that isn't covered above.
[]<typename T>( std::vector<T> const& v ) { return v.size(); }
1 In addition, RTTI is stored (typeid), and the cast-back-to-original-type operation is included.
Let's break the line apart:
std::function
This is a declaration for a function taking no parameters, and returning no value. If the function returned an int, it would look like this:
std::function<int()>
Likewise, if it took an int parameter as well:
std::function<int(int)>
I suspect your main confusion is the next part.
[]() { FNAME(); };
The [] part is called a capture clause. Here you put variables that are local to the declaration of your lambda, and that you want to be available within the lambda function itself. This is saying "I don't want anything to be captured". If this was within a class definition and you wanted the class to be available to the lambda, you might do:
[this]() { FNAME(); };
The next part, is the parameters being passed to the lambda, exactly the same as if it was a regular function. As mentioned earlier, std::function<void()> is a signature pointing to a method that takes no parameters, so this is empty also.
The rest of it is the body of the lambda itself, as if it was a regular function, which we can see just calls the function FNAME.
Another Example
Let's say you had the following signature, that is for something that can sum two numbers.
std::function<int(int, int)> sumFunc;
We could now declare a lambda thusly:
sumFunc = [](int a, int b) { return a + b; };
Not sure if you're using MSVC, but here's a link anyway to the lamda expression syntax:
http://msdn.microsoft.com/en-us/library/dd293603.aspx
Lambdas with captures (stateful lambdas) cannot be assigned to each other since they have unique types, even if they look exactly the same.
To be able to store and pass around lambdas with captures, we can use "std::function" to hold a function object constructed by a lambda expression.
Basically "std::function" is, to be able to assign lambda functions with different content structures to a lambda function object.
Exp :
auto func = [](int a){
cout << "a:" << a << endl;
};
func(40);
//
int x = 10;
func = [x](int a){ //ATTENTION(ERROR!): assigning a new structure to the same object
cout << "x:" << x << ",a:" << a << endl;
};
func(2);
So the above usage will be incorrect.
But if we define a function object with "std::function":
auto func = std::function<void(int)>{};
func = [](int a){
cout << "a:" << a << endl;
};
func(40);
//
int x = 10;
func = [x](int a){ //CORRECT. because of std::function
//...
};
int y = 11;
func = [x,y](int a){ //CORRECT
//...
};

How can I get around specifying variables in decltype expressions?

Assume I have the following exemplary function:
template <typename Fn> auto call(Fn fn) -> decltype(fn()) {
return fn();
}
The important thing about this function is that its return type depends on its template parameter, which can be inferred. So ultimately, the return type depends on how the function is called.
Now, we also have a test class:
struct X {
int u;
auto test() -> decltype(call([this]() -> double {this->u = 5; return 7.4;})) {
return call([this]() -> double {this->u = 5; return 7.4;});
}
};
as you can see, X::test calls call, returning the same return value. In this case, the return type is trivially given as double, but let's assume for a bit we didn't know what call does and that the lambda has a more complicated return type.
If we try to compile this, the compiler will complain, because we're using this at the top level (not in a scope that would allow an expression):
error: lambda-expression in unevaluated context
error: invalid use of ‘this’ at top level
However, I have to use the capture of the lambda which I pass to call in order to get call's return type right. How would you suggest to get around this, while still leaving the lambda?
Note: Of course I could move the lambda to be an operator() of some helper type, which I instantiate with a copy of the this pointer, but I'd like to avoid that boilerplate.
I think the real error to be concerned about is "lambda-expression in unevaluated context". You can't use a lambda in an unevaluated context because every lambda expression has a unique type. That is, if decltype([]{}) were allowed it would deduce a different type than []{} in some other context. I.e. decltype([]{}) fn = []{}; wouldn't work.
Unless you want to just explicitly write the return type rather than have it deduced, I don't think you have any choice but to create a real type that you can use in the contexts you need, with whatever boilerplate that entails.
Although if changing test to not be a member function is acceptable then you could use the fact that lambda's can deduce their return type by omitting it if the body is only a single return statement:
template <typename Fn> auto call(Fn fn) -> decltype(fn()) {
return fn();
}
struct X {
int u;
};
int main() {
auto test = [](X *x) { return call([x]() -> double {x->u = 5; return 7.4; });};
X x;
test(&x);
}
It would be nice if the trailing return type syntax for functions had the same property. I'm not sure why it doesn't.
It seems to be a made up (construed, artificial) question, since
If you get the lambda from somewhere else, then it's named and no problem binding this.
If you're not getting the lambda from somewhere else, then you know the result type.
In short, as the problem is currently stated (as I'm writing this answer) there's no problem except one imposed by your own will.
But if you insist on that, well, just pass this as an argument instead of binding it via the lambda definition. Then for the call to call, bind the argument. But, perhaps needless to say, since that only solves a made-up problem it's a real Rube Goldberg construction, a decent into over-flowering needless complexity that doesn't solve anything real outside its own intricacies.
What was the original real problem, if any?
You shouldn't always copy-and-paste function body to decltype. The point of introducing late-specified return type was that you'll be able to somehow infer correct return type from arguments.
e.g. auto f(T x) -> decltype(g(x)) { return h(), g(x); }, not -> decltype(h(), g(x))
So, in your case, double test() is enough, because we know behavior of call and we know return type of lambda function we pass to it.
In more complex case, we should reduce code inside decltype, by using knowledge about call and other stuff.

Recursive call in lambda (C++11) [duplicate]

This question already has answers here:
Closed 10 years ago.
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