5

I want to capture a 'reference' to a lambda, and I thought that a function pointer would do the trick, as in:

int (*factorial)(int) = [&](int x){
    return (x < 2)
        ? 1
        : x * factorial(x - 1);
};

but I get cannot convert from main::lambda<......> to int(_cdecl *)(int).

What's the proper way to point to a lambda then?

sircodesalot
  • 11,231
  • 8
  • 50
  • 83

3 Answers3

6

Since the lambda is not stateless, it cannot be converted to a function pointer. Use std::function instead.

std::function<int(int)> factorial  = [&](int x){
  return (x < 2)
      ? 1
      : x * factorial(x - 1);
};
Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • 1
    This has non-trivial overhead costs, as a warning, compared to "raw" lambdas. Each call is roughly equivalent to calling a `virtual` method. It isn't that bad, but compared to the work being done in the call, is significant. – Yakk - Adam Nevraumont Jun 28 '13 at 13:48
  • @Yakk Yes, you do pay the cost of `std::function`'s type erasure; I was just looking for that answer from a few weeks ago to link to :) – Praetorian Jun 28 '13 at 13:49
  • What does that mean `not stateless`? Also, @Yakk what are the overhead costs? – sircodesalot Jun 28 '13 at 13:49
  • @sircodesalot A stateful lambda is a lambda that captures state. Ie, if you have anything within the `[]` at the start of the lambda, your lambda has state. I edited my answer with information about the overhead costs. – Yakk - Adam Nevraumont Jun 28 '13 at 13:50
  • @sircodesalot Not stateless means it's capturing variables within its context. In this case, it is recursively referring to the `std::function` object `factorial`. – Praetorian Jun 28 '13 at 13:51
  • 1
    @Praetorian: I guess you were looking for [this one](http://stackoverflow.com/a/9088690/1137388). – Cassio Neri Jun 28 '13 at 14:44
5

This would be closest to what you have already:

std::function<int (int)> factorial = [&](int x){
    return (x < 2)
        ? 1
        : x * factorial(x - 1);
};

normally you could also use auto, but in this case it doesn't work because the function is recursive.

Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
5

You already have good answers. The following is just a curiosity but I wouldn't suggest you to use it.

As said by others answer, the lambda factorial tries to capture itself and hence it's not stateless. Therefore, it's not convertible to a function pointer.

Lambdas don't need to capture global or static objects, so if you make factorial a global or static variable then you don't need to capture it and this works fine (gcc 4.7.2)

    #include <iostream>

    typedef int (*function)(int);

    int main() {
        static function factorial = [](int x){
            return (x < 2) ? 1 : x * factorial(x - 1);
        };
        std::cout << factorial(5) << '\n';
    }

You can also create a factory like this:

    #include <iostream>

    typedef int (*function)(int);

    function make_factorial() {
        static function factorial = [](int x){
            return (x < 2) ? 1 : x * factorial(x - 1);
        };
        return factorial;
    }

    int main() {
        auto factorial = make_factorial();
        std::cout << factorial(5) << '\n';
    }

If you want to obfuscate even more :-) then eliminate the typedef:

    // This is a function returning a pointer to a function taking an int and returning an int.
    int (*(make_factorial)())(int) {
        static int (*factorial)(int) = [](int x){
            return (x < 2) ? 1 : x * factorial(x - 1);
        };
        return factorial;
    }
Cassio Neri
  • 19,583
  • 7
  • 46
  • 68