【问题标题】:How does the compiler generate a closure from a deleted-default-ctor lambda?编译器如何从已删除的默认 ctor lambda 生成闭包?
【发布时间】:2023-03-13 00:30:01
【问题描述】:

我想知道如何以这种方式使用带有已删除默认构造函数的 lambda:

[](){}; // how is this translated by the compiler?

但这不起作用:

auto l = [](){std::cout << "lambda expr\n";}; // which ctor is invoked?

decltype (l) g; // doesn't work
  • 因为在 C++ 20 之前它不起作用,但 C++ 20 使 lambda 默认可构造。

  • 如果没有可调用的构造函数,该对象是如何存在的?

【问题讨论】:

  • "[](){}; // how is this translated by the compiler?" - 放入godbolt.org或者反汇编生成的二进制文件就知道了。
  • 我不太明白你的问题。以前没有可调用的默认 ctor,现在有了。有问题吗?你是在问编译器是如何在之前说我们可以使用ctor的? Lambda 很神奇,伙计!编译器作者使用什么源代码来使它工作真的不重要吗?
  • @AsteroidsWithWings:我很清楚:我在 C++11 标准中说过,它说一个不捕获任何对象的 lamda 则 lambda 有一个已删除的默认 ctor,因此在这样的表达式中如何可以在删除 default-ctor 的同时构造闭包:[]{}?
  • 从 lambda 表达式创建 lambda 对象时,编译器不需要调用默认 c'tor。它很可能有特殊的逻辑。您可能会感到沮丧,但它之所以有效,是因为 C++ 标准说它应该有效,而编译器编写者使之成为现实。
  • 这也不是以这种方式工作的唯一实例。 std::initializer_listlimited in how user programs can construct it。然而,标准规定{1, 2, 3} 可以简单地变成std::initializer_list

标签: c++ c++11 lambda


【解决方案1】:

这有点像问:如果int 没有构造函数,那么在计算整数字面量时,int 对象从何而来?

编译器可以在不调用构造函数的情况下创建对象,只需生成在内存中设置对象所需的程序集或机器代码。它只是不允许您在不调用构造函数的情况下创建各种类类型的对象。 (尽管在 C++20 中,这将因P0593 而改变。)

当编译器看到一个包含 lambda 表达式的表达式时,它会继续并生成在内存中设置闭包对象的代码。没有义务将该代码打包为函数,就像打包构造函数中的代码一样。编译器甚至可能生成一些只有它知道如何调用的构造函数。从用户的角度来看,不涉及构造函数。

【讨论】:

  • 嘿,厄运,我自己用了int这个例子:)
  • 非常感谢!
  • @Maestro 如果此答案解决了您的问题,请考虑通过单击复选标记接受它
【解决方案2】:

编译器不是在编写 C++;它不受与我们相同的规则的约束。

在 C++20 之前 我们 无法使用 C++ 默认构造闭包类型。但这并没有改变标准说 lambda 表达式产生闭包类型的对象这一事实。所以,编译器必须让它做那件事,它从来不需要通过一个默认的构造函数来做。没关系!从来没有任何规则规定它必须使用那种机器。

很抱歉,没有更令人满意的答案,但实际上只是“因为标准是这样说的”。

另请参阅:编译器为什么不能定义内置类型(例如int)?因为!

【讨论】:

  • 非常感谢!
猜你喜欢
  • 1970-01-01
  • 2014-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多