Lambda捕获列表和复制

3

我有一段简单的代码:

#include <iostream>
#include <functional>

struct Copy
{
    Copy(){}
    Copy(const Copy&)
    {
        std::cout << "Copied!\n";
    }
};

int main() 
{
    Copy copy;
    std::function<void()> func = [=]{(void)copy;};
    return 0;
}

它调用了copy-ctor两次,我希望只调用一次。我知道在这个简化的例子中可以使用auto,但我需要将其存储以供稍后使用,因此auto不是选项。

我的问题是:有没有一种方法可以使用=捕获列表存储lambda,并且只捕获对象的一个副本?


我很惊讶实例被复制了,因为你创建的函数实际上并没有被调用。你使用的编译器和版本是什么? - Some programmer dude
@JoachimPileborg:当然有两个副本:一个是将copy复制到lambda中,另一个是在将lambda(其中有一个Copy成员)复制到std::function中时发生的。 - Mankarse
1个回答

5

有两个副本:一个用于将copy复制到lambda中,另一个出现在将lambda(具有Copy成员)复制到std::function中时。

如果您想要一份拷贝和一份移动,则需要使Copy对象可移动:

#include <iostream>
#include <functional>

struct Copy
{
    Copy(){}
    Copy(const Copy&)
    {
        std::cout << "Copied!\n";
    }
    Copy(Copy&&)
    {
        std::cout << "Moved!\n";
    }
};
//Prints:
//Copied!
//Moved!
int main()
{
    Copy copy;
    std::function<void()> func = [=]{(void)copy;};
    return 0;
}

这个是否符合标准?我的意思是Lambda是否必须具有移动构造函数/运算符=? - ixSci
@ixSci:是的——请参见[expr.prim.lambda]/19:“与lambda表达式相关联的闭包类型具有已删除(8.4.3)默认构造函数和已删除的复制赋值运算符。它具有隐式声明的复制构造函数(12.8),并且可能具有隐式声明的移动构造函数(12.8)。[注意:复制/移动构造函数的隐式定义方式与任何其他隐式声明的复制/移动构造函数的隐式定义方式相同。—注]”。(感谢您的提问,关于“mutable”的说明是错误的) - Mankarse
谢谢Mankarse!我对“可能具有隐式声明的移动构造函数”感到有些困惑。GCC和Clang有它,而MSVC没有。我不确定是否可以提交错误报告,因为这种行为并非标准强制要求,只是“没有被禁止”。 - ixSci
提交到 MS connect - ixSci
@ixSci: "may" 只是指移动构造函数只有在所有捕获的对象都可移动时才存在。对于复制构造函数条款,没有 "may",因为被复制捕获的对象必须是可复制的,所以复制构造函数始终可用。(有关隐式声明构造函数的更多信息,请参见 §12.8/9§12.8/11 -- 我认为 MSVC 的行为是不符合规范的)。 - Mankarse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接