为什么 C++ 中的 lambda 从不 DefaultConstructible

Why is a lambda in C++ never DefaultConstructible

我有不捕获任何东西的 lambda,比如

[](){};

我有一个模板 class,其中包含这样一个 lambda。由于 lambda 不包含 non-static 数据成员,也不包含虚函数,因此它应该是空的 class 和 DefaultConstructible。它只是一种可用于模板元编程的策略class。我想知道,为什么这样的 class 不是 C++ 标准默认构造的。

旁注: 问了一个不同的问题,尽管标题似乎非常相似。它询问如何在没有可用默认构造函数的情况下创建无状态 lambda-object。我在问为什么没有可用的默认构造函数。

Lambda 旨在创建然后使用。因此,该标准说“不,它们没有默认构造函数”。制作一个的唯一方法是通过 lambda 表达式或相同的副本。

它们不是旨在让它们的类型成为您随身携带和使用的东西。这样做有违反 ODR 的风险,并且要求编译器避免 ODR 违规会使符号处理过于复杂。

但是,在 C++17 中,您可以围绕函数指针编写无状态包装器:

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)...);
  }
};

并且由于 [](){} 上的 operator void(*)() 在 C++17 中是 constexprfunction_pointer_t<+[](){}> 是一个什么都不做的函数对象,它是 DefaultConstructible。

这实际上并没有包装 lambda,而是 lambda 生成的指向函数的指针。

我假设您熟悉类型、对象和表达式之间的区别。在C++中,lambda特指一个lambda表达式。这是表示非平凡 object 的便捷方式。然而,这很方便:您可以通过编写代码自己创建一个类似的对象。

现在,根据 C++ 规则,每个表达式都有一个类型,但该类型不是 lambda 表达式的用途。这就是为什么它是未命名且唯一的类型的原因——C++ 委员会认为不值得定义这些属性。类似地,if 它被定义为具有默认构造函数,标准应该定义行为。使用当前规则,无需定义默认构造函数的行为。

正如您所注意到的,对于 [](){} 的特殊情况,定义默认构造函数是微不足道的。但那没有意义。您会立即遇到第一个难题:应该为什么 lambda 定义默认构造函数? lambda 的哪个子集简单到可以有一个体面的定义,又复杂到足以引起人们的兴趣?没有共识,你不能指望这个标准化。

请注意编译器供应商,作为扩展,已经可以提供这个了。标准化通常遵循现有实践,请参阅 Boost。但是,如果没有编译器供应商单独认为值得,他们为什么会一致这么认为?

对于 C++20,无状态 lambda 是默认可构造的。所以,现在这种操作是有效的:

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