Why is a lambda in C++ never DefaultConstructible

With C++20, stateless lambdas are default constructible. So, now this kind of operations are valid:

auto func = []{};
decltype(func) another_func;

I'll assume that you're familiar with the difference between types, objects and expressions. In C++, lambda specifically refers to a lambda expression. This is a convenient way to denote a non-trivial object. However, it's convenience: you could create a similar object yourself by writing out the code.

Now per the C++ rules every expression has a type, but that type not what lambda expressions are intended for. This is why it's an unnamed and unique type - the C++ committee didn't think it worthwhile to define those properties. Similarly, if it was defined to have a default ctor, the Standard should define the behavior. With the current rule, there's no need to define the behavior of the default ctor.

As you note, for the special case of [](){} it's trivial to define a default ctor. But there's no point in that. You immediately get to the first hard question: for what lambda's should the default ctor be defined? What subset of lambda's is simple enough to have a decent definition, yet complex enough to be interesting? Without a consensus, you can't expect this to be standardized.

Note that compiler vendors, as an extension, could already offer this. Standardization often follows existing practice, see Boost. But if no compiler vendor individually thinks it worthwhile, why would they think so in unison?


Lambdas are intended to be created then used. The standard thus says "no, they don't have a default constructor". The only way to make one is via a lambda expression, or copies of same.

They are not intended for their types to be something you keep around and use. Doing so risks ODR violations, and requiring compilers to avoid ODR violations would make symbol mangling overly complex.

However, in C++17 you can write a stateless wrapper around a function pointer:

template<auto fptr>
struct function_pointer_t {
  template<class...Args>
  // or decltype(auto):
  std::result_of_t< std::decay_t<decltype(fptr)>(Args...) >
  operator()(Args&&...args)const
    return fptr(std::forward<Args>(args)...);
  }
};

And as operator void(*)() on [](){} is constexpr in C++17, function_pointer_t<+[](){}> is a do-nothing function object that is DefaultConstructible.

This doesn't actually wrap the lambda, but rather the pointer-to-function that the lambda produces.