为什么C ++中的lambda永远不会是DefaultConstructible

时间:2016-08-02 14:01:51

标签: c++ c++11 lambda default-constructor

我有没有抓住任何东西的lambdas,比如

[](){};

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

旁注: Understanding how Lambda closure type has deleted default constructor提出了一个不同的问题,虽然标题似乎非常相似。它询问如何在没有可用的默认构造函数的情况下创建无状态lambda对象。我问为什么没有可用的默认构造函数。

3 个答案:

答案 0 :(得分:8)

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生成的指向函数的指针。

答案 1 :(得分:2)

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

现在根据C ++规则,每个表达式都有一个类型,但该类型不是lambda表达式的用途。这就是为什么它是一个未命名和独特的类型--C ++委员会认为定义这些属性是不值得的。类似地,如果它被定义为具有默认ctor,则标准应该定义行为。使用当前规则,无需定义默认ctor的行为。

正如您所注意到的,对于[](){}的特殊情况,定义默认ctor是微不足道的。但这没有意义。你立刻得到了第一个难题:为什么lambda应该定义默认的ctor? lambda的哪个子集很简单,有一个不错的定义,但复杂到足以引起兴趣?如果没有达成共识,你不能指望这是标准化的。

请注意,编译器供应商作为扩展已经可以提供此功能。标准化通常遵循现有的做法,参见Boost。但是如果没有编译器供应商认为它是值得的,他们为什么会这样认为是一致的呢?

答案 2 :(得分:0)

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

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