Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are captureless lambda guaranteed to be empty by the standard?

I'm searching for a way to identify empty (captureless) lambdas from other lambdas in a template function. I'm currently using C++17 but I'm curious for C++20 answers too.

My code looks like this:

template<typename T>
auto func(T lambda) {
    // The aguments of the lambdas are unknown

    if constexpr (/* is captureless */) {
        // do stuff
    }
}

Is it guaranteed by the C++ standard (17 or 20) that a captureless lambda, which is convertible to a function pointer, will also make std::is_empty yield true?

Take this code as an example:

auto a = []{}; // captureless
auto b = [c = 'z']{}; // has captures

static_assert(sizeof(a) == sizeof(b)); // Both are the same size
static_assert(!std::is_empty_v<decltype(b)>); // It has a `c` member
static_assert(std::is_empty_v<decltype(a)>); // Passes. It is guaranteed?

Live example

like image 659
Guillaume Racicot Avatar asked Jan 27 '20 17:01

Guillaume Racicot


People also ask

What is a lambda closure C++?

Introduction. In C++, lambda expression constructs a closure, an unnamed function object capable of capturing variables in scope. It still sounds ambiguous, at least to me. Closure is a general concept in programming that originated from functional programming.

What does [&] mean in C++?

It's a lambda capture list and has been defined in C++ from the C++11 standard. [&] It means that you're wanting to access every variable by reference currently in scope within the lambda function.

What is the type of a lambda?

A type lambda lets one express a higher-kinded type directly, without a type definition. For instance, the type above defines a binary type constructor, which maps arguments X and Y to Map[Y, X] . Type parameters of type lambdas can have bounds, but they cannot carry + or - variance annotations.


1 Answers

No, in fact, the standard explicitly grants permission for lambdas to have a size that doesn't line up with their declaration. [expr.prim.lambda.closure]/2 states

The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression. [ Note: This determines the set of namespaces and classes associated with the closure type ([basic.lookup.argdep]). The parameter types of a lambda-declarator do not affect these associated namespaces and classes. — end note ] The closure type is not an aggregate type. An implementation may define the closure type differently from what is described below provided this does not alter the observable behavior of the program other than by changing:

  • the size and/or alignment of the closure type,

  • whether the closure type is trivially copyable ([class.prop]), or (2.3)

  • whether the closure type is a standard-layout class ([class.prop]).

An implementation shall not add members of rvalue reference type to the closure type.

emphasis mine

So this allows the implementation to give the lambda a member even if it is capture-less. I don't think any implementation ever would, but they are legally allowed to do so.

like image 93
NathanOliver Avatar answered Sep 30 '22 15:09

NathanOliver