I am trying to use recursive lambda functions with auto keyword as below.
#include <iostream>
using namespace std;
int main()
{
auto func = []()->void{
static int x = 0;
cout << x << endl;
if (x < 5) {
func();
x++;
}
};
func();
return 0;
}
But it is throwing compiler error as below.
main.cpp: In lambda function:
main.cpp:19:13: error: use of ‘func’ before deduction of ‘auto’
func();
^~~~
I understood that we can achieve the same with std::function. But I wanted to know why I am getting error by using 'auto'.
I went through below stack overflow questions.
Can lambda functions be recursive?
Recursive lambda functions in C++11
Use of 'auto func(int)' before deduction of 'auto' in C++14
But I couldn't figure out why auto with lambda is throwing error in this case. Can anyone please let me know why I am getting this error?
The problem is not the return-type of the lambda expression. The problem is the type of the lambda itself.
Each lambda expression is a unique anonymous type.
In your code, the compiler knows that the lambda returns void, but it doesn't yet know the type of the lambda, since it has not fully parsed it yet.
To give a counter example to highlight the issue.
#include <iostream>
int main()
{
int x;
auto func = [&](){
// func is going to become an int here, but the compiler does not know that yet
// it has to parse the whole expression first.
x = func;
return 5;
}(); // <-- calling the lambda and assigning the return value to func
}
You cannot make lambda recursive. Lambdas cannot be recursive because they don't have a name. See this: https://en.cppreference.com/w/cpp/language/lambda
an unnamed function object capable of capturing variables in scope.
Here lambda generate before initialization, thus the compiler gives you an error.
The only way to implement it in real lambda calculus is to use Y combinator. But I think that's meaningless in C++. Especially here you are not using enclosure at all.
In C++, there's another way to implement it: use std::function to replace auto, and then call the std::function rather than lambda instead.
Related
I've been daydreaming about this language where you can define different functions with the same name but whose arguments are of different type (or length).
Here's a naive example, assuming a C-like syntax.
struct vect {
int x;
int y;
};
struct guy {
struct vect pos;
char *name;
};
struct guy new_guy(vect v, char *name) {
struct guy g;
g.pos = v;
g.name = name;
return g;
}
struct guy new_guy(int x, int y, char *name) {
struct vect v;
v.x = x;
v.y = y;
return new_guy(v, name);
}
int get_x(struct vect v) {
return v.x;
}
int get_x(struct guy g) {
return g.pos.x;
}
The point would be in avoiding having long names like: get_vect_x and get_guy_x, etc. The compiler knows what types we are using to call a function so it shouldn't be a problem to figure out which definition to use.
There could also be different definitions for different number of arguments.
From Wiki:
In some programming languages, function overloading or method overloading is the ability to create multiple functions of the same name with
different implementations. Calls to an overloaded function will run a specific implementation of that function appropriate to the context of the call,
allowing one function call to perform different tasks depending on context.
wiki link giving definition of function overloading
Java is capable of this, which would lead me to wonder if C++ is (much less experienced with it than Java). Declaring methods of the same name with different parameters or similar parameters different types is supported, even with constructors. This is likely easily implemented in Java because it's a statically typed language. A quick way to check if this is possible is to look at the docs of a particular language's standard libraries for constructors that take different combinations of parameters.
Don't understand why I can do
const OK = uint64(0)
const OK = int(unsafe.Sizeof(uint64(0)))
but not this?
const NOK = binary.Size(uint64(0))
It's explained in the specification.
Package unsafe is implemented in the compiler. The expression unsafe.Sizeof(uint64(0)) can be evaluated at compile time. It is a constant expression.
The function plain function call binary.Size(uint64(0)) cannot be evaluated at compile time. It is not constant expression.
Constant declarations require a constant expression.
One thing to mention here is that if the type in question is from a type parameter, then the specification considers the type variably sized, so some code, possibly reflection? is run to figure the size. So using unsafe.Sizeof() as such has to do something at runtime to figure out the size, even if the actual type is able to be known at compile time.
func [T constraints.Integer] WhatIsTheFrequencyKenneth(n T) uintptr {
return unsafe.Sizeof(n)
}
fmt.Println("I had to generate code to tell you this: ", WhatIsTheFrequencyKenneth(int64(42)))
Lately, I've been doing a little digging into the C++11 std and was playing around with unique_ptrs.
Let's say I have a function which returns a unique_ptr to an integer.
unique_ptr<int> GetUniquePtr(int i)
{
return make_unique<int>(i);
}
In my main function, I am able to take the address of the value returned by the function. This means that the expression must evaluate to an lvalue
int main()
{
cout << &(GetUniquePtr(5));
}
I know if I assign the function call to a unique pointer, the move consturctor of the unique_ptr will be called, treating the returned value as an rvalue reference.
int main()
{
unique_ptr<int> uPtr = GetUniquePtr(5);
}
This dual behaviour of returning unique_ptr kind of confuses me, as I was of the impression that unique_ptr returned from a function call is always evaluated as an rvalue.
Can anyone shed some light on what's actually going on?
I use C++11 lambdas quite a lot, and I've often run into compile errors on multiline lambdas because I forgot to add the return type, as is expected, but I recently ran into one example that doesn't have this issue. It looks something like this:
auto testLambda = [](bool arg1, bool arg2)
{
if (arg1)
{
if (!arg2)
{
return false;
}
return true;
}
return false;
};
This compiles just fine even though there's no return type specified. Is this just Visual Studio being dumb and allowing something it shouldn't, or can lambdas just always deduce intrinsic types?
I tried this with return values of all ints or floating point values and it also compiled just fine. I just found this to be really surprising so I wanted to be absolutely sure how it works before I start making assumptions and omitting return types that might break later on.
Lambdas follow the same template deduction rules as auto-returning functions:
Template argument deduction is used in declarations of functions, when deducing the meaning of the auto specifier in the function's return type, from the return statement.
For auto-returning functions, the parameter P is obtained as follows: in T, the declared return type of the function that includes auto, every occurrence of auto is replaced with an imaginary type template parameter U. The argument A is the expression of the return statement, and if the return statement has no operand, A is void(). After deduction of U from P and A following the rules described above, the deduced U is substituted into T to get the actual return type:
auto f() { return 42; } // P = auto, A = 42:
// deduced U = int, the return type of f is int
If such function has multiple return statements, the deduction is performed for each return statement. All the resulting types must be the same and become the actual return type.
If such function has no return statement, A is void() when deducing.
Note: the meaning of decltype(auto) placeholder in variable and function declarations does not use template argument deduction.
I saw this code. Can you explain me, whats mean this piece of code:
auto main() ->
{
}
What is difference between this and follow code:
int main()
{
return 0;
}
auto main() is illegal in as per the resolution of core issue 1669.
The intent of whatever person gave you that code was probably to use return type deduction to figure out the return type. This happens in C++11 lambdas, and is being extended to most functions (main being one exception) in C++14.