Passing capturing lambda as function pointer

Cory Kramer picture Cory Kramer · Feb 26, 2015 · Viewed 157k times · Source

Is it possible to pass a lambda function as a function pointer? If so, I must be doing something incorrectly because I am getting a compile error.

Consider the following example

using DecisionFn = bool(*)();

class Decide
{
public:
    Decide(DecisionFn dec) : _dec{dec} {}
private:
    DecisionFn _dec;
};

int main()
{
    int x = 5;
    Decide greaterThanThree{ [x](){ return x > 3; } };
    return 0;
}

When I try to compile this, I get the following compilation error:

In function 'int main()':
17:31: error: the value of 'x' is not usable in a constant expression
16:9:  note: 'int x' is not const
17:53: error: no matching function for call to 'Decide::Decide(<brace-enclosed initializer list>)'
17:53: note: candidates are:
9:5:   note: Decide::Decide(DecisionFn)
9:5:   note: no known conversion for argument 1 from 'main()::<lambda()>' to 'DecisionFn {aka bool (*)()}'
6:7:   note: constexpr Decide::Decide(const Decide&)
6:7:   note: no known conversion for argument 1 from 'main()::<lambda()>' to 'const Decide&'
6:7:   note: constexpr Decide::Decide(Decide&&)
6:7:   note: no known conversion for argument 1 from 'main()::<lambda()>' to 'Decide&&'

That's one heck of an error message to digest, but I think what I'm getting out of it is that the lambda cannot be treated as a constexpr so therefore I cannot pass it as a function pointer? I've tried making x const as well, but that doesn't seem to help.

Answer

Shafik Yaghmour picture Shafik Yaghmour · Feb 26, 2015

A lambda can only be converted to a function pointer if it does not capture, from the draft C++11 standard section 5.1.2 [expr.prim.lambda] 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.

Note, cppreference also covers this in their section on Lambda functions.

So the following alternatives would work:

typedef bool(*DecisionFn)(int);

Decide greaterThanThree{ []( int x ){ return x > 3; } };

and so would this:

typedef bool(*DecisionFn)();

Decide greaterThanThree{ [](){ return true ; } };

and as 5gon12eder points out, you can also use std::function, but note that std::function is heavy weight, so it is not a cost-less trade-off.