为什么C ++ 11不能将不可复制的仿函数移动到std :: function?

时间:2012-08-01 22:04:36

标签: c++ function lambda c++11

//------------------------------------------------------------------------------
struct A
{
    A(){}
    A(A&&){}
    A& operator=(A&&){return *this;}
    void operator()(){}

private:
    A(const A&);
    A& operator=(const A&);

    int x;
};

//------------------------------------------------------------------------------
int main()
{
    A a;
    std::function<void()> func(std::move(a));
}

'A :: A':无法访问在类'A'

中声明的私有成员

似乎当我通过引用或const捕获某些内容时,我可以创建一个不可复制的lambda。但是,当我这样做时,实际上可以将它赋予std::function

3 个答案:

答案 0 :(得分:21)

简短的回答是,C ++ 11规范要求A CopyConstructiblestd::function一起使用。

答案很长,因为std::function会删除构造函数中的仿函数类型,因此存在此要求。为此,std::function必须通过虚函数访问函子的某些成员。这些包括调用运算符,复制构造函数和析构函数。由于这些是通过虚拟调用访问的,因此无论您是否实际使用std::function的复制构造函数,析构函数或调用操作符,它们都会被“使用”。

答案 1 :(得分:0)

std::function 要求函子是可复制的。

这是一个随意的设计决定。可能的替代方案是:

  • 允许使用不可复制的函子,但尝试复制生成的 std::function 会导致崩溃/异常。
  • 允许使用不可复制的函子,并且 std::function 本身始终是不可复制的。
  • ...

如果复制结果 std::function,不可能只要求可复制性,因为它可以在不同的 TU(翻译单元)中复制。

所以,如果你问我,目前的行为是较小的邪恶。

答案 2 :(得分:-1)

这是Visual Studio中的一个错误。它试图省略一个副本(实际上它应该试图进行移动),这需要一个可访问的复制构造函数。最好的解决方案是简单地声明复制构造函数/赋值运算符,而不是定义它们。该类仍然是不可复制的,但代码将编译,因为VS永远不会尝试实际调用复制构造函数。