milleniumbug
milleniumbug

Reputation: 15834

Why can't my constexpr function return a lambda?

I found this piece of code doesn't work:

typedef int (*fp)(int a, int b);

constexpr fp addition()
{
    return [](int a, int b){ return a+b; };
}

#include <iostream>

int main()
{
    fp fun = addition();
    std::cout << fun(2,2);
}

It gives me error

cexpr.cpp: In function 'constexpr int (* addition())(int, int)':
cexpr.cpp:5:43: error: call to non-constexpr function 'addition()::<lambda(int,
int)>::operator int (*)(int, int)() const'

Why is that? I'm not calling it here.

Direct approach works:

typedef int (*fp)(int a, int b);

#include <iostream>

int main()
{
    fp fun = [](int a, int b){ return a+b; };
    std::cout << fun(2,2);
}

I'm using MinGW with g++ version 4.7.2.

Upvotes: 21

Views: 2727

Answers (3)

rici
rici

Reputation: 241931

The error message gcc gave you was precise and correct:

error: call to non-constexpr function 'addition()::
             <lambda(int,int)>::
             operator int (*)(int, int)() const'

I've reformatted it a bit and added emphasis. By coercing the lambda to a function pointer, you're implicitly calling the automatically-created conversion function from lambda to pointer to function of type "auto (int, int)->int", which is not a constexpr function because the automatically-created conversion function is not declared constexpr (and the standard doesn't require it to be).

Upvotes: 5

Andy Prowl
Andy Prowl

Reputation: 126562

Your function fp() does not return a literal type, therefore it cannot be a constexpr function:

From 7.1.5: "The definition of a constexpr function shall satisfy the following constraints:

  • it shall not be virtual (10.3);
  • its return type shall be a literal type;
  • each of its parameter types shall be a literal type;
  • its function-body shall be = delete, = default, or a compound-statement that contains only
    • null statements,
    • static_assert-declarations
    • typedef declarations and alias-declarations that do not define classes or enumerations,
    • using-declarations,
    • using-directives,
    • and exactly one return statement;"

I do not think there is any bug here, and especially nothing related to lambdas as mentioned in an earlier answer: variables simply cannot be declared inside of a constexpr function.

Upvotes: 9

Rapptz
Rapptz

Reputation: 21317

According to N3376 working draft of the standard section 5.19 [expr.const]:

Certain contexts require expressions that satisfy additional requirements as detailed in this sub-clause; other contexts have different semantics depending on whether or not an expression satisfies these requirements. Expressions that satisfy these requirements are called constant expressions. [ Note: Constant expressions can be evaluated during translation.— end note ]

It goes on to say:

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2), but subexpressions of logical AND (5.14), logical OR (5.15), and conditional (5.16) operations that are not evaluated are not considered [ Note: An overloaded operator invokes a function.— end note ]:

Which lists under it:

— a lambda-expression (5.1.2);

So while I don't know enough standardese, I believe this says that a constexpr shouldn't have a lambda expression inside.

Upvotes: 7

Related Questions