5

I wonder how a compiler treats lambda functions as opposed to regular functions. Even excluding the capture-list, as I think it's called, it seems to behave slightly differently.

For example, as used in my last post, Trying to pass a constexpr lambda and use it to explicitly specify returning type, I used a constexpr lambda and passed it as a regular function parameter. I quote a part of the answer.

Parameters to constexpr functions are not themselves constexpr objects - so you cannot use them in constant expressions.

template <typename Lambda_T>
constexpr static auto foo(Lambda_T l) {
    return std::array<event, (l())>{};
} 
// Compiles with GCC (C++17), though ill-formed (according to the answer of my last post)

Though, what catches my eye is that this does compile passing a constexpr lambda, but does not compile passing a constexpr regular (global) function. What causes this difference? And are there other differences of behaviour of the compiler between regular functions and lambda-functions?

Edit: Example of Lambda-implementation

foo([](){ return 4; }); // C++17 Lambda's are implicitly constexpr

The lambda is basically a wrapper for the value in this case.

Edit: Global function

Whenever a global function is passed, the compiler will complain - as opposed to using a lambda - that this function, regardless of whether it is defined constexpr or not, cannot be used in a constant condition:

prog.cc:8:20: error: 'l' is not a constant expression
3
  • Can you show your lambda implementation? Commented Jan 27, 2019 at 11:39
  • 2
    It will compile if you pass any functor initialized by a constant expression. It will compile too if you replace l() by fptr() where fptr is a function pointer initialized by a constant expression. The only difference I see, is that when called with a function argument, the function-to-pointer conversion applied to the argument to initialize the parameter may not be assumed to be a constant expression. But I suspect in c++20 it should be assumed to be a constant initialization and in c++17 it is even more obscure. Commented Jan 27, 2019 at 11:57
  • @Oliv Oops, I just figured you already said the same thing while I was writing my answer. Commented Jan 27, 2019 at 12:12

1 Answer 1

1

Removing some extraneous stuff from your snippet, we get

template<typename T>
constexpr void foo(T t)
{
    constexpr int i = t();
}

constexpr int f() { return 42; }
auto l = []{ return 42; }

Remarks:

  1. You are attempting to use t() as a constexpr within foo. foo could in fact be a normal function and still behave the same.

  2. A lambda isn't a function. It is an anonymous struct with an operator().

    struct L { constexpr int operator()() const { return 42; } };
    

    T is deduced as a type equivalent to L in the call foo(l).

  3. T is deduced as int(*)() in the call foo(f).

  4. In both cases, t isn't a constexpr within foo.


From [expr.const]

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions: [...]

  • an lvalue-to-rvalue conversion unless [...]

    • a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable subobject of such an object, or

    • a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;

Calling through a int(*)() requires a lvalue-to-rvalue conversion. t isn't an object defined with constexpr, neither did it begin its lifetime within the evaluation of t(). Therefore t() isn't a constexpr in foo(f).

Calling operator() doesn't require a lvalue-to-rvalue conversion. Since there is no member access, it is simply a constexpr function call. Therefore t() is a constexpr in foo(l).

There is one more step from core constant expressions to constant expressions, but isn't important for the discussion here.

Sign up to request clarification or add additional context in comments.

Comments

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.