当前位置: 首页 > 知识库问答 >
问题:

使用lambda捕获类后没有合适的复制构造函数

蓟俊杰
2023-03-14

我有以下代码:

#include <iostream>

class Foo
{public:
    Foo() {}
    int a;
};

int main()
{
    Foo foo;

    auto lambda = [=]() mutable { std::cout << foo.a; };

}

在我需要向我的Foo类添加副本构造函数之前,一切都很顺利:

Foo(Foo& t) {}

它不会再编译了,这给了我们一个信息:

类“Foo”:没有可用的复制构造函数,或者复制构造函数声明为“显式”

我已经使lambda可变,因为我不想捕获一个const Foo,但我认为正在发生的是lambda不能被复制。另一个编译器有一个更有用的错误消息:

错误:使用已删除的函数“main()::

以及:

主::

但是我真的不明白。这个隐式删除的函数是lambda的移动构造函数吗?我不明白为什么仅仅向捕获的类(而不是lambda)添加复制构造函数就会发生这种情况。

这就是我想象的lambda/仿函数的样子:

class lambda
{public:

     Foo foo; // <---- My captured variable/class
     void operator()(){ std::cout << foo.a; }
}

那么,将这些lambda中的一个复制到另一个涉及调用Foo的赋值运算符或复制构造函数?我不明白仅仅是Foo拥有一个拷贝构造函数是如何导致这个失败的,或者什么是“格式错误的”。我注意到的另一件事是,当lambda通过引用捕获时没有问题[

编辑:它不在此编译器上编译:

https://www.jdoodle.com/online-compiler-c /

我在Visual Studio上,它无法编译。然而,当我做了一个小得多的例子,它会编译器,但仍然强调错误。在我的大型项目中,它不编译。

共有3个答案

钦英发
2023-03-14

要获得编译错误,您应该在C 11或C 14标准下编译此代码。在C17中它是有效的。演示。

让我们考虑一下

struct Foo {
    Foo() {}
    Foo(Foo&) {}
};

在C17中我们可以写

auto f = Foo{};

但是在C 11/14中,这一行将无法编译。原因是在C17中,我们有强制性的复制省略,以及复制构造函数调用的正确性,这将是错误的,因为Foo

这直接转化为lambda(rafix07的答案解释了如何),因为它通过值捕获Foo。lambda本身很好。例如,你可以写

[=] { std::cout << foo.a; };

但是lambda的移动构造函数是格式错误的,在C 11/14中,它必须是格式良好的

auto lambda = [=] { std::cout << foo.a; };

编译。

尉迟国发
2023-03-14
auto lambda = [=]() mutable { std::cout << foo.a; };

在右侧创建临时闭包。在此基础上,通过调用编译器生成的默认移动构造函数来构造另一个临时闭包。

closure c(closure{});

移动构造函数的默认实现只是一个接一个地移动所有数据成员:

struct closure {
    Foo foo;

    closure (closure&& theOther) : foo(std::move(theOther.foo))   // <--- [1]
    {}                              // binding rvalue ref to lvalue ref
};

你的Fooctor接受Foo

它在MSVC中工作,因为它有一个扩展来处理这样的事情。在G/Clang下,它必须失败。

const Foo

卫胜
2023-03-14

复制构造函数原型是A(const A

 类似资料:
  • 问题内容: 只有最后一部分(我的意思是我仅对此有问题) 当我编译它时,我没有合适的构造函数错误。为什么是这样??顺便说一下,Spirtokouto类的目的是要增加一个计数值(权重)。我可以将一个班级扩展到> 1个班级吗? 问题答案: Box类有两个构造函数:,但它们都不带四个参数,而您要用四个参数来调用它,因此请更改此参数: 对此: 调用必须首先在构造函数中进行。 我可以将一个班级扩展到 > 1个

  • 问题内容: 我正在使用Jackson来将json数组反序列化为某些对象。这是我的课: 错误: 我一直在使用GSON,但由于性能问题需要放弃它。当我切换到Jackson时,我只是向所有类添加了默认构造函数,这可能是不必要的,因为没有定义其他构造函数… 编辑: 哦,JSON看起来像这样: 问题答案: 我没有与Jackson一起工作,但我想问题是Business类是成员类而不是静态的。 杰克逊需要做的是

  • 从javase api 8开始,是不推荐的。因此,动态生成是首选的导出对象方式,如下所示: null 我的问题是,当出现在JavaE8 api中时,为什么编译器会出错?

  • 我有一个Employee实体类,它有许多列。我想从这个类中获取一些列,因此我使用了DTO。我创建了一个新的BaseEmployee类,并在EmployeeRepository中编写了查询。但当我尝试运行应用程序时,我会遇到这样的错误:“类中没有合适的构造函数错误”。 我的dto类: Jpa仓库: 错误:

  • 我正在运行一个应用程序,可以在选择或捕捉它们后查看多个图像。当我运行应用程序时,ImageView部分似乎有问题,它说: