c++lambdastaticlanguage-designc++23

Why doesn't the C++ standard implicitly define a lambda capturing nothing as `static` by default?


C++23 allows to define a lambda as static. i.e. If a lambda captures nothing, then it can be defined as static:

// with superfluous argument `this`, less efficient.
auto fn1 = [](int a, int b) { return a + b; }; 

// no argument `this`, more efficient!
auto fn2 = [](int a, int b) static { return a + b; }; 

I just wonder:

Why doesn't the C++ standard implicitly define a lambda capturing nothing as static by default?


Solution

  • When lambdas were introduced, nobody took into account the fact that non capturing lambdas did not need to pass the lambda object's this pointer as an argument to operator(). When they realized this in C++23, it was too late to change the default behavior that existed since C++11. The reason why they couldn't change the behavior is described in P1169R3

    However, we can’t simply change such lambdas because this could break code. There exists code that takes a template parameter of callable type and does decltype(&F::operator()), expecting the resulting type to be a pointer to member type (which is the only thing it can be right now). If we change captureless lambdas to have a static call operator implicitly, all such code would break for captureless lambdas. Additionally, this would be a language ABI break. While lambdas shouldn’t show up in your ABI anyway, we can’t with confidence state that such code doesn’t exist nor that such code deserves to be broken.

    Though they considered making this behavior implementation defined by allowing a user to switch this behavior with a compiler option, this was rejected because it would be an observable behavior change that is usually not a good option for implementation defined choices.