Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Construction of lambda object in case of specified captures in C++

Starting from C++20 closure types without captures have default constructor, see https://en.cppreference.com/w/cpp/language/lambda:

If no captures are specified, the closure type has a defaulted default constructor.

But what about closure types that capture, how can their objects be constructed?

One way is by using std::bit_cast (provided that the closure type can be trivially copyable). And Visual Studio compiler provides a constructor for closure type as the example shows:

#include <bit>

int main() {
    int x = 0;
    using A = decltype([x](){ return x; }); 

    // ok everywhere
    constexpr A a = std::bit_cast<A>(1);
    static_assert( a() == 1 );

    // ok in MSVC
    constexpr A b(1);
    static_assert( b() == 1 );
}

Demo: https://gcc.godbolt.org/z/dnPjWdYx1

Considering that both Clang and GCC reject A b(1), the standard does not require the presence of this constructor. But can a compiler provide such constructor as an extension?

like image 493
Fedor Avatar asked Oct 22 '21 17:10

Fedor


People also ask

What are lambda captures?

Captures default to const value. By default, variables are captured by const value . This means when the lambda is created, the lambda captures a constant copy of the outer scope variable, which means that the lambda is not allowed to modify them.

What is the correct syntax for lambda expression in C++11?

Lambdas can both capture variables and accept input parameters. A parameter list (lambda declarator in the Standard syntax) is optional and in most aspects resembles the parameter list for a function. auto y = [] (int first, int second) { return first + second; };

What is the type of lambda expression C++?

The type of a lambda expression is unspecified. But they are generally mere syntactic sugar for functors. A lambda is translated directly into a functor.

How do you capture a member variable in lambda C++?

To capture the member variables inside lambda function, capture the “this” pointer by value i.e. std::for_each(vec. begin(), vec. end(), [this](int element){ //.... }


1 Answers

But what about closure types that capture, how can their objects be constructed?

You can't. They can only be created from the lambda expression.

And no, bit_cast does not "work everywhere". There is no rule in the C++ standard which requires that any particular lambda type must be trivially copyable (or the same size as its capture member for that matter). The fact that no current implementations break your code does not mean that future implementations cannot.

And it definitely won't work if you have more than one capture member.

Just stop treating lambdas like a cheap way to create a type. If you want to make a callable type with members that you can construct, do that:

#include <bit>

int main() {
    struct A
    {
      int x = 0;
      constexpr auto operator() {return x;}
    };

    // ok everywhere
    constexpr A b(1);
    static_assert( b() == 1 );
}
like image 74
Nicol Bolas Avatar answered Sep 22 '22 22:09

Nicol Bolas