I wonder if it's possible to write a function that returns a lambda function in C++11. Of course one problem is how to declare such function. Each lambda has a type, but that type is not expressible in C++. I don't think this would work:
auto retFun() -> decltype ([](int x) -> int)
{
return [](int x) { return x; }
}
Nor this:
int(int) retFun();
I'm not aware of any automatic conversions from lambdas to, say, pointers to functions, or some such. Is the only solution handcrafting a function object and returning it?
You don't need a handcrafted function object, just use std::function, to which lambda functions are convertible:
This example returns the integer identity function:
std::function<int (int)> retFun() {
return [](int x) { return x; };
}
For this simple example, you don't need std::function.
From standard §5.1.2/6:
The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.
Because your function doesn't have a capture, it means that the lambda can be converted to a pointer to function of type int (*)(int):
typedef int (*identity_t)(int); // works with gcc
identity_t retFun() {
return [](int x) { return x; };
}
That's my understanding, correct me if I'm wrong.
Though the question specifically asks about C++11, for the sake of others who stumble upon this and have access to a C++14 compiler, C++14 now allows deduced return types for ordinary functions. So the example in the question can be adjusted just to work as desired simply by dropping the -> decltype... clause after the function parameter list:
auto retFun()
{
return [](int x) { return x; }
}
Note, however, that this will not work if more than one return <lambda>; appears in the function. This is because a restriction on return type deduction is that all return statements must return expressions of the same type, but every lambda object is given its own unique type by the compiler, so the return <lambda>; expressions will each have a different type.
You can return lambda function from other lambda function, since you should not explicitly specify return type of lambda function. Just write something like that in global scope:
auto retFun = []() {
return [](int x) {return x;};
};
You should write like this:
auto returnFunction = [](int x){
return [&x](){
return x;
}();
};
to get your return as a function, and use it like:
int val = returnFunction(someNumber);
If you do not have c++ 11 and are running your c++ code on micro controllers for example. You can return a void pointer and then perform a cast.
void* functionThatReturnsLambda()
{
void(*someMethod)();
// your lambda
someMethod = []() {
// code of lambda
};
return someMethod;
}
int main(int argc, char* argv[])
{
void* myLambdaRaw = functionThatReturnsLambda();
// cast it
auto myLambda = (void(*)())myLambdaRaw;
// execute lambda
myLambda();
}
Related
It is fine to compile these code in c11
double(*p1)(double) = [](double a) { return sqrt(a); };
double(*p2)(double) = [&](double a) { return sqrt(a); };
But there is the following error in compilation in c17
double(*p2)(double) = [&](double a) { return sqrt(a); };
cannot convert test_pointer_to_function::test_method()::<lambda(double)> to double (*)(double) in initialization double(*p2)(double) = [&](double a) { return sqrt(a); };
What is the correct type for this lamda function?
There's no "correct" function pointer type for lambda expression with non-empty lambda-capture. Such closure objects are not convertible to ordinary function pointers.
If you want to be able to convert closure object to ordinary function pointer type, make sure you have nothing in the [] part of lambda expression. This applies to C++11 and later, including C++17.
Each lambda has its own unique type. Normally, if you need to assign a lambda to a variable, you use auto for its type. If you need a known type (e.g. you are going to store lambdas in a container), you can use std::function with the same signature as your lambda. In your example, this will be
std::function<double(double)> p2 = [&](double a) { return sqrt(a); };
(but note that you generally lose some efficiency this way).
Only non-capturing lambdas, i.e. lambdas with empty [], are convertible to a function pointer, like in your example:
double(*p1)(double) = [](double a) { return sqrt(a); };
Your C++11 compiler should not have accepted
double(*p2)(double) = [&](double a) { return sqrt(a); };
I have to return an int and a function object to the caller, I was thought of returning a tuple like make_tuple(int,[](some){}) I am now on GCC that doesn't support decltpe(auto) as a return type, is ther any way i could make my return type as std::tuple<int,auto> myfun() right now I've been doing like below(but not sure)
auto myfun()->decltype(make_tuple(100,p))
{
auto p=[](some){};
return make_tuple(100,p);
}
what I am doing is ok?
No, since p is not available at that scope, and a lambda expression shall not appear in unevaluated context (which is decltype). (See more here)
You can, however, wrap it in an std::function:
std::tuple<int, std::function<void(some)>> myfun()
{
std::function<void(some)> p = [](some){};
return std::forward_as_tuple(100, p);
}
I have the following code:
int main() {
auto f = [] {
if (1) return [] { return 1; };
else return [] { return 2; };
};
return f()();
}
which raises the following compiler error using GCC 5.2.1:
error: inconsistent types ‘main()::<lambda()>::<lambda()>’ and
‘main()::<lambda()>::<lambda()>’ deduced for lambda
return type else return [] { return 2; };
Now obviously those two types look to be the same, so I'm not sure if this is GCC with a misleading error message or if it's actually a bug. According to my knowledge this should compile; the lambda return type should be deduced to be std::function<int()>. Interestingly, if I pre-declare the lambda return and return the same variable twice, it works.
Can anyone shed some light as to what is happening? I found similar looking questions, many attributed to GCC bugs, but this looks different.
Now obviously those two types are the same,
No, they're not. The type of every lambda expression is a unique, distinct type.
From [expr.prim.lambda]/3:
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below.
Therefore, return type deduction for f fails and does not result in std::function<int()>. The latter is an unrelated library type that isn't somehow magically the "common type" of any closure type.
Of course each of the unique closure types can be converted to std::function<int()>, so if you provide the return type, everything works:
auto f = []() -> std::function<int()> {
return 1 ? []() { return 1; }
: []() { return 2; };
};
Or, as a plain function:
std::function<int()> f() {
return 1 ? []() { return 1; }
: []() { return 2; };
}
Every lambda has its own, unique type:
The lambda expression constructs an unnamed prvalue temporary object of unique unnamed non-union non-aggregate type[...].
From here, emphasize mine.
Also, lambdas have nothing to do with std::function, that is another different type. In particular,
[] { return 1; }
and
[] { return 2; }
have different types. This is why deduction fails.
Those types are not the same. Each lambda is an instance of a unique, unnamed type. std::function is a template that can be implicitely converted to from appropriate callable objects including lambdas, but no instantiation of std::function is type or parent type of any lambda so it cannot be deduced.
However, you can tell the compiler that you want it to return std::function and it will work:
auto f = []() -> std::function<int()> {
if (1) return [] { return 1; };
else return [] { return 2; };
}
I am trying to learn lambdas in C++, but stumbled on something I can't quite understand.
Here is code:
#include <iostream>
typedef double Func(double);
double applyFunc(Func f, double x)
{
return f(x);
}
int main()
{
std::cout << applyFunc([](double x) {return x + 1;}, 3) << std::endl;
}
Now this works just fine (prints "4"), i.e. type of the lambda expression used is exactly double (*)(double).
But if I add closure to the lambda expression, like:
int main()
{
int n = 5;
std::cout << applyFunc([n](double x) {return x + n;}, 3) << std::endl;
}
Then I get an error from the compiler:
In function ‘int main()’:
error: cannot convert ‘main()::__lambda0’ to ‘double (*)(double)’ for argument ‘1’ to ‘double applyFunc(double (*)(double), double)’
3) << std::endl;
^
And I don't understand why is that. I mean, from the point of view of applyFunc() it still receives a pointer to a function taking double argument and returning double, and it doesn't know that we used variable 'n' from context, so the type of lambda expression should be the same, as in the first example, right?
I would very appreciate help, thank you in advance!
A lambda is convertable to a function pointer only if it does not have a capture, we can see this by going to the draft standard section 5.1.2 Lambda expressions which says (emphasis mine):
The closure type for a lambda-expression with no lambda-capture has a
public non-virtual non-explicit const conversion function to pointer
to function having the same parameter and return types as the closure
type’s function call operator. The value returned by this conversion
function shall be the address of a function that, when invoked, has
the same effect as invoking the closure type’s function call operator.
This is an alternative solution which does not rely on this conversion:
template <typename Callable>
double applyFunc(Callable f, double x)
{
return f(x);
}
Update
If you are interested in the difference between using std::function and templates then you should read std::function vs template. There are many good answers there and a lot of food for thought.
Each lambda expression returns an object with a distinct type. If the lambda expression does not capture any variables, it can be converted to a a function pointer type of an appropriate signature (i.e., the return type and the arguments need to agree with those of the lambda expression). When there is a variable captured, the entity created can't be represented by a plain function. Instead, the lambda expression yields an object of class type with a function call operator. That is, your second code uses a lambda expression yielding an object of a class which is roughly equivalent to this:
class lambda {
int n;
public:
lambda(int n): n(n) {}
double operator()(double x) const { return x + n; }
};
I have this code:
void foo(void (*bar)()) {
bar();
}
int main() {
foo([] {
int x = 2;
});
}
However, I'm worried that this will suffer the same fate as:
struct X { int i; };
void foo(X* x) {
x->i = 2;
}
int main() {
foo(&X());
}
Which takes the address of a local variable.
Is the first example completely safe?
A lambda that captures nothing is implicitly convertible to a function pointer with its same argument list and return type. Only capture-less lambdas can do this; if it captures anything, then they can't.
Unless you're using VS2010, which didn't implement that part of the standard, since it didn't exist yet when they were writing their compiler.
Yes I believe the first example is safe, regardless of the life-time of all the temporaries created during the evaluation of the full-expression that involves the capture-less lambda-expression.
Per the working draft (n3485) 5.1.2 [expr.prim.lambda] p6
The closure type for a lambda-expression with no lambda-capture has a
public non-virtual non-explicit const conversion function to pointer
to function having the same parameter and return types as the closure
type’s function call operator. The value returned by this conversion
function shall be the address of a function that, when invoked, has
the same effect as invoking the closure type’s function call operator.
The above paragraph says nothing about the pointer-to-function's validity expiring after evaluation of the lambda-expression.
For e.g., I would expect the following to work:
auto L = []() {
return [](int x, int y) { return x + y; };
};
int foo( int (*sum)(int, int) ) { return sum(3, 4); }
int main() {
foo( L() );
}
While implementation details of clang are certainly not the final word on C++ (the standard is), if it makes you feel any better, the way this is implemented in clang is that when the lambda expression is parsed and semantically analyzed a closure-type for the lambda expression is invented, and a static function is added to the class with semantics similar to the function call operator of the lambda. So even though the life-time of the lambda object returned by 'L()' is over within the body of 'foo', the conversion to pointer-to-function returns the address of a static function that is still valid.
Consider the somewhat analagous case:
struct B {
static int f(int, int) { return 0; }
typedef int (*fp_t)(int, int);
operator fp_t() const { return &f; }
};
int main() {
int (*fp)(int, int) = B{};
fp(3, 4); // You would expect this to be ok.
}
I am certainly not a core-c++ expert, but FWIW, this is my interpretation of the letter of the standard, and I feel it is defendable.
Hope this helps.
In addition to Nicol's perfectly correct general answer, I would add some views on your particular fears:
However, I'm worried that this will suffer the same fate as ..., which
takes the address of a local variable.
Of course it does, but this is absolutely no problem when you just call it inside foo (in the same way your struct example is perfectly working), since the surrounding function (main in this case) that defined the local variable/lambda will outlive the called function (foo) anyway. It could only ever be a problem if you would safe that local variable or lambda pointer for later use. So
Is the first example completely safe?
Yes, it is, as is the second example, too.