Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't my constexpr function return a lambda?

Tags:

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.

like image 710
milleniumbug Avatar asked Dec 29 '12 21:12

milleniumbug


People also ask

Can a lambda be constexpr?

Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): A lambda expression may be declared as constexpr or used in a constant expression when the initialization of each data member that it captures or introduces is allowed within a constant expression.

Can a function return constexpr?

A constexpr function is a function that can be invoked within a constant expression. A constexpr function must satisfy the following conditions: It is not virtual. Its return type is a literal type.

Is constexpr always compile time?

A constexpr (which is short for “constant expression”) variable can only be a compile-time constant. If the initialization value of a constexpr variable is not a constant expression, the compiler will error.


2 Answers

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.

like image 116
Andy Prowl Avatar answered Oct 19 '22 18:10

Andy Prowl


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.

like image 45
Rapptz Avatar answered Oct 19 '22 16:10

Rapptz