在C ++ 11中不允许重新定义lambda,为什么?

时间:2013-09-12 05:10:09

标签: c++ c++11 lambda language-lawyer

示例:

#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省略了允许复制可构造性的动机理由。

5 个答案:

答案 0 :(得分:68)

你似乎认为那两个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。当然,在这方面,您从编译器获得的错误消息可能会更清楚......

答案 1 :(得分:46)

  

的类型   λ-表达   (也是闭包对象的类型)是唯一,未命名的非   联合类类型

所以就像你正在做以下事情:

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

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

std::function<void()> f = []{};
f = []{}; //ok

答案 2 :(得分:8)

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

答案 3 :(得分:5)

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

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都有一个唯一的类型,但这并不是你得到这个错误的原因。此示例显示即使两个lambdas具有相同的类型,它仍然无法复制它。但是,您可以将其复制到新变量。这就是您的错误消息抱怨丢失operator=而不是他们的类型不同的原因。虽然每个拥有它自己类型的lambda也没有帮助你。

答案 4 :(得分:2)

如果我们可以将一个lambda分配给另一个不同类型的lambda,我们如何将函数体/定义从该lambda复制到另一个?如果我们如此固执,那么我们可以使用某个成员std::function - 类似的类型将被复制。但那将违反不支付等等等等的“C ++规则”。