13

I am trying to assign a pointer to lambda function to pointer to another lambda function. The code will speak for itself:

#include <iostream>

int main(int argc, char *argv[]) {

    auto l1 = []() { std::cout << "Lambda 1!" << std::endl; };
    auto l2 = [] { std::cout << "Lambda 2!" << std::endl; };

    auto l1p = &l1;
    l1p = &l2; // Why can't I do this assignment?
    return 0;
}

Since the return types and argument of both lambda functions are the same, why can't I do this assignment?

0

3 Answers 3

17

[expr.prim.lambda]/2:

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.

That is, two closure types are always entirely distinct and unrelated. However, in your example, as neither of both lambdas captures anything, they can be converted to a function pointer of type void(*)().
So perhaps you meant to do

void (*l1p)() = l1;
l1p = l2;
Sign up to request clarification or add additional context in comments.

6 Comments

In C++11(+) I would prefer to use std::function<void()> l1f = l1;l1f = l2; just as it easier to read.
@SimonKraemer please don't. The overhead of std::function is not worth the slight syntactical improvement. Just use a typedef.
@Quentin I just checked the compiler output. I am really surprised about the massive overhead. Thanks for pointing it out.
@SimonKraemer std::function's name really is not scary enough. It's not "a function", it's a type-erased functionoid container. I've heard of crazy compilers managing to optimize through it in some cases, but you probably don't want to rely on it ;)
@SimonKraemer it is a typesafe wrapper ... for any callable. A function pointer, a hand written class with an operator(), a lambda, etc. This may require heap allocation (to store state) (some implementions have a small object optimization), but does involve a vtable or equivalent for dispatching. The call overhead is similar to a virtual function call at (), which is slightly more than a function pointer call, but harder to inline.
|
9

As an addition to Columbo's answer, you can have both type deduction and lambda-to-function-pointer decaying by using operator + :

auto l1p = +l1; // l1p is void (*)()
//         ^
l1p = l2;

Comments

7

Let's remove the syntactic sugar that the lambda functions provide us:

struct lambda1 {
  void operator () {
    std::cout << "Lambda 1!" << std::endl;
  }
};
struct lambda2 {
  void operator () {
    std::cout << "Lambda 2!" << std::endl;
  }
};
int main(int argc, char *argv[]) {

    auto l1 = Lambda1{};
    auto l2 = Lambda2{};

    auto l1p = &l1; // l1p is a Lambda1 *
    l1p = &l2; // &l2 is a Lambda2 *
    return 0;
}

This isn't the exact transformation done by the compiler, but I think it suffices to examine the issue:

The two lambdas have each an own type, that is totally unrelated to their arguments, captured variables or return type. And of course, the types of lambdas are to each other unrelated, so you can obviously not assign a pointer to one from the address of the other.


The solution in the other answer with the function pointer is pretty nice. If there weren't a "you only pay for it when you use it" doctrine for C++, we could have made lambda functions like

struct SomeLambda
  : public LambdaBase<
        Capture<int>,
        Arguments<bool>,
        Return<void>> {
  // ...
};
/*
  [integer]
  (bool flag) {
    if (flag) cout << integer;
  }
*/

But for that to make any sense the base would need to be polymorphic (has a virtual member function), and that's a cost you don't need if you don't intend to do what you wanted.

2 Comments

I get the point of the example. But question aside, are C++ lambdas really syntactic sugar for (C++1) closures?
As far as I know, yes ( stackoverflow.com/q/7627098/1116364) they're only sugar.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.