【问题标题】:Why isn't a lambda that captures variables by reference convertible to a function pointer?为什么通过引用捕获变量的 lambda 不能转换为函数指针?
【发布时间】:2014-11-01 19:03:33
【问题描述】:

如果我有一个通过引用 ([&] {}) 捕获所有自动变量的 lambda,为什么不能将它转换为函数指针?普通函数可以修改变量,就像 lambda 可以通过引用捕获所有内容一样,那为什么不一样呢?

我想换句话说,带有& 捕获列表的 lambda 和一个常规函数之间的功能区别是什么,使得 lambda 不能转换为函数指针?

【问题讨论】:

  • 必须将所有这些捕获变量的引用(实际上是指针)存储在某处。将“按引用捕获”视为“按值捕获地址”。
  • @IgorTandetnik:如果我们使用 GC(可能但很少见)或接受内存泄漏,这将是可解决的。
  • @Deduplicator:我想编译器可以在运行时动态生成程序集 thunk;我已经看到这样做了(如果您想知道的话,是由 Microsoft 的 ATL 完成的)。不过,这在按价值捕获时同样有效;通过引用捕获既无帮助也无害。
  • @IgorTandetnik:当然,我忽略了 OP 对引用的固定。
  • 这是您对 C++ lambda 的唯一疑惑吗?我有一个更基本的问题:为什么明确禁止写下 lambda 的类型?您可以将其分配给auto 变量或将其类型作为模板参数传递,仅此而已。根本没有语法来编写接受 lambda 的非模板函数。 lambdas 的类型是唯一不能写下来的,这使得它们低于二等公民。就个人而言,如果语言功能被削弱是一种基本方式,我不会再考虑它。

标签: c++ c++11 lambda function-pointers


【解决方案1】:

让我们以一个平凡的 lambda 为例:

Object o;
auto foo = [&]{ return o; };

foo 的类型是什么样的?它可能看起来像这样:

struct __unique_unspecified_blah
{
    operator()() const {
        return o;
    }

    Object& o;
};

你能创建一个指向operator() 的函数指针吗?不,你不能。该函数需要一些来自其对象的额外信息。这与您无法将典型的类方法转换为原始函数指针的原因相同(没有this 所在的额外第一个参数)。假设您确实创建了一些 this 指针 - 它怎么知道从哪里获取 o

问题的“引用”部分不相关 - 如果您的 lambda 捕获任何东西,那么它的 operator() 将需要引用对象中的某种存储。如果它需要存储,它不能转换为原始函数指针。

【讨论】:

  • “这与你不能将典型的类方法转换为原始函数指针的原因相同。”不,那是电话会议的事情。现在,如果你的意思是一个需要更少参数的原始函数指针(比如不需要this)......
  • @Deduplicator:考虑到其余的解释,我认为这正是他的意思......
  • @EdS.:只是 G++ 很乐意为您将成员函数指针转换为常规函数指针,而且它们工作顺利。
  • @Deduplicator:我猜是非虚拟的?我不太明白它在一般情况下如何工作。
  • @Deduplicator 如何将成员函数指针转换为常规函数指针?我以为他们会是不同的类型(比如void(*)() vs void(Obj::*)()
【解决方案2】:

我猜换句话说,a 之间的功能区别是什么? 带有& 捕获列表和常规函数的 lambda,使得 lambda 不能转换为函数指针?

引用虽然不是对象,但需要存储在某个地方。常规函数不能访问另一个函数的局部变量;只有可以引用局部变量的引用(例如作为参数)。可以使用 & 作为捕获默认值的 Lambda,因为可以捕获所需的每个变量。
换句话说:常规函数没有状态。带有捕获变量的闭包对象确实具有状态。所以一个闭包对象不能被简化为一个常规函数,因为状态会丢失。

【讨论】:

  • @Deduplicator 我并没有试图说这完全不可能,因为你可以做一些很好的技巧(例如使用静态地图)。我将尝试创建一个示例。
  • 稍后再找。
猜你喜欢
  • 2013-10-03
  • 2015-10-15
  • 2013-04-29
  • 1970-01-01
  • 1970-01-01
  • 2012-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多