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

C++ C+;中不允许重新定义lambda+;11,为什么?,c++,c++11,lambda,language-lawyer,C++,C++11,Lambda,Language Lawyer,例如: #include <functional> int main() { auto test = []{}; test = []{}; return 0; } #包括 int main(){ 自动测试=[]{}; test=[]{}; 返回0; } 这会在gcc 4.7.2中发出以下错误消息: test.cpp: In function ‘int main()’: test.cpp:5:13: error: no match for ‘operator

例如:

#include <functional>

int main() {
  auto test = []{};
  test = []{};
    
  return 0;
}
#包括
int main(){
自动测试=[]{};
test=[]{};
返回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()>&’
test.cpp:在函数“int main()”中:
test.cpp:5:13:错误:“test=main()::{}”中的“operator=”不匹配
测试。cpp:5:13:注:候选人为:
test.cpp:4:16:注意:main():&main()::操作符=(const main():&)
test.cpp:4:16:注意:参数1没有从'main()::'到'const main()::&'的已知转换
根据标准5.1.2.3(重点矿山):

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

-闭合类型的尺寸和/或对齐方式

-闭包类型是否可复制(第9条)

-闭合类型是否为标准布局类别(第9条),或

-闭合类型是否为POD类(第9条)

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

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

这就像你在做以下事情:

struct {} a;
struct {} b;
a = b; // error, type mismatch
如果要将具有相同签名的不同lambda分配给同一变量,请使用
std::function

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

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

您似乎认为这两个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;
}
#包括
#包括
#包括
int main(){
自动测试=[]{};
自动测试2=[]{};

STD::CUT::值:如果我们可以把一个lambda分配给另一个不同类型的lambda,我们如何复制函数体/定义从lambda到另一个lambda?如果我们是如此顽固,那么我们可以使用一些成员<代码> STD::函数< /C> >类型,就是要被复制的类型。但是这将违反OL C++规则。t paying blah blah…

无法执行此操作的原因是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;
}
模板空f(T x1)
{
T x2=x1;//复制构造函数存在,此操作将成功。
x2=x1;//赋值运算符,已删除并将导致错误
}
int main()
{
f([]{});
返回0;
}

其他答案指出,每个lambda都有一个唯一的类型,但这不是出现该错误的原因。此示例显示,即使两个lambda具有相同的类型,它仍然无法复制它。但是,您可以将其复制到新变量。这是错误消息抱怨missin的原因g
operator=
并不是说它们的类型不同。虽然每个lambda都有自己的类型,但这对您也没有多大帮助。

它没有尝试使用复制构造函数。它尝试使用赋值运算符。不,阻止您使用赋值运算符的是5.1.2.20与一个lambda表达式有一个deleted(8.4.3)默认构造函数和deleted copy赋值运算符。它有一个隐式声明的copy构造函数(12.8),也可能有一个隐式声明的move构造函数(12.8)。(好吧,这和lambda的类型不同这一事实有关)如果你在第一个lambda之前放置一个
+
,它会神奇地开始工作。@omnipotenentity这是纯魔法,我不知道它是如何工作的。
+
操作符是否启用了一些特殊功能!@johanneschaub litb我想我解决了这个难题。注释有点长,所以我自己回答了。参考:[expr.prim.lambda]/3“lambda表达式的类型[…]是唯一的、未命名的非并集类类型-称为闭包类型”@DyP正要在标准中搜索它,但您的搜索速度更快了。谢谢:)我不知道,单词unique的用法很能说明这一点。;)谢谢!假设每个lambda表达式都是一个宏,用重载的
运算符()替换未命名的类定义的表达式
,以及保存捕获变量的成员变量。即使两个类的结构相同,它们仍然是不同的类型。即使它们是相同的类型,您仍然无法复制它们,因为复制构造函数已被删除(请参阅C++11标准第5.1.2.20节)。编译器甚至还没有达到需要在失败之前检查类型是否匹配的程度。这就是为什么会出现“不匹配运算符=”错误的原因。请参见我在回答中给出的示例。或者,由于它们是非捕获的,
void(*f)()
也可以。这样效率更高。类型是唯一的,因为类型编码要调用的特定函数;函数只是
操作符()
类型。这允许在通用算法中内联函数,这在函数指针或
std::function
@JanHudec:某种程度上是不可能的,即使两个lambda表达式相同,它们仍然是不同的类型。@user1131467:如果有两个具有相同内容的类,它们仍然是不同的类型.+1.您应该在答案中添加引用标准(顺便说一句,是5.1.2/19,而不是5.1.2/20)