63

例子:

#include <functional>

int main() {
  auto test = []{};
  test = []{};
    
  return 0;
}

这会在 gcc 4.7.2 中发出以下错误消息:

test.cpp: In function ‘int main()’:
test.cpp:5:13: error: no match for ‘operator=’ in ‘test = <lambda closure object>main()::<lambda()>{}’
test.cpp:5:13: note: candidate is:
test.cpp:4:16: note: main()::<lambda()>& main()::<lambda()>::operator=(const main()::<lambda()>&) <deleted>
test.cpp:4:16: note:   no known conversion for argument 1 from ‘main()::<lambda()>’ to ‘const main()::<lambda()>&’

从标准 5.1.2.3(强调我的):

一个实现可以定义不同于下面描述的闭包类型,前提是这不会改变程序的可观察行为,除非改变:

— 闭包类型的大小和/或对齐方式,

— 闭包类型是否可简单复制(第 9 条)

— 闭包类型是否是标准布局类(第 9 条),或者

— 闭包类型是否是 POD 类(第 9 条)。

据我所知,这就是我要面对的。它试图使用已删除的赋值运算符并失败。我很想知道是否有一个简单的解决方法,以及更广泛地说,允许对 lambdas 省略复制可构造性的动机是什么。

4

5 回答 5

71

您似乎认为这两个 lambda 具有相同的类型,但事实并非如此。每个都创建自己的类型:

#include <functional>
#include <type_traits>
#include <iostream>

int main() {
  auto test = []{};
  auto test2 = []{};
  std::cout << std::is_same< decltype( test ), decltype( test2 ) >::value << std::endl;
  return 0;
}

将打印0。当然,在这方面,您从编译器获得的错误消息可能会更清楚一些......

于 2013-09-12T05:27:59.557 回答
47

lambda 表达式的类型(也是闭包对象的类型)是唯一的、未命名的非联合类类型

因此,就像您正在执行以下操作:

struct {} a;
struct {} b;
a = b; // error, type mismatch

如果std::function要将具有相同签名的不同 lambda 分配给同一变量,请使用此选项。

std::function<void()> f = []{};
f = []{}; //ok
于 2013-09-12T05:21:20.027 回答
8

无法重新定义 Lambda,因为每个 lambda 都是不同的、匿名的、不兼容的类型。std::function仅当您将它们传递给能够推断出该类型的模板化函数(如 ctor)时,它们才能被复制。

于 2013-09-12T05:26:52.060 回答
6

您无法执行此操作的原因是 lambda 表达式的复制赋值运算符已被声明为已删除,请参阅标准的第 5.1.2/20 节。有关更清晰的(对于 clear 的不寻常定义),请参阅此代码示例

template<class T> void f(T x1)
{
  T x2 = x1; // copy constructor exists, this operation will succeed.
  x2 = x1; // assignment operator, deleted and will cause an error
}
int main()
{
  f([]{});
  return 0;
}

其他答案指出每个 lambda 都有一个唯一的类型,但这不是您收到该错误的原因。这个例子表明,即使两个 lambda 具有相同的类型,它仍然无法复制它。但是,您可以将其复制到新变量中。这就是您的错误消息抱怨丢失operator=而不是类型不同的原因。尽管每个 lambda 都有自己的类型也对您没有多大帮助。

于 2013-10-30T22:40:38.880 回答
2

如果我们可以将一个 lambda 分配给另一个不同类型的 lambda,我们如何将函数体/定义从该 lambda 复制到另一个?如果我们这么固执,那么我们可以使用一些类似成员std::function的类型作为将被复制的类型。但这违反了不付钱的 C++ 规则……

于 2013-09-12T05:40:26.957 回答