c++recursionlambdaundefined-behaviorc++23

Why does Deducing-This lambda require `this` to be a reference or capturing variables by reference?


Why does this code output garbage on GCC like there is a UB?

auto data = std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto output = [data](this auto self, size_t i) {
    if (i >= 10) {
        return;
    }
    std::print("{}, ", data[i]);
    self(i + 1);
};
output(0);

Changing to capture data by reference or self as a reference makes it look fine.

Link to Compiler Explorer


Solution

  • Can narrow it down: it's a GCC bug, featured at least in version 15.2, where for an object created by a lambda expression with deduced this by value, the intialization code isn't produced if any of captures by value is a type with not-defaulted copy or move constructors, a simplest test case here returns 1 whenever at least one constructor of the two is user-defined as not-default:

    struct A {
      A() {};
      A(const A&) {}
      //A(const A&) = default;
      A(A&&) {}
      //A(A&&) = default;
      int n = 42;
    };
    
    int main() {
       auto l = [data = A()](this auto) {
         return data.n != 42;
       };
      return l();
    }
    

    If lambda expression would have other captures, they will not be initialized either, and capture-by-reference turns into capture-by-value, having unique address but uninitialzied.

    Default constructor have no effect on this behaviour.