C++ 使std::function需要复制构造函数的基本原理

C++ 使std::function需要复制构造函数的基本原理,c++,c++14,C++,C++14,我最近试着做这样的事情: auto x = std::make_unique<int>(1); auto l = [y = std::move(x)]() { return *y; }; std::function<void()> f(std::move(l)); //error, requires copy construction auto x=std::使_唯一(1); 自动l=[y=std::move(x)](){return*y;}; std::函数f(std

我最近试着做这样的事情:

auto x = std::make_unique<int>(1);
auto l = [y = std::move(x)]() { return *y; };
std::function<void()> f(std::move(l)); //error, requires copy construction
auto x=std::使_唯一(1);
自动l=[y=std::move(x)](){return*y;};
std::函数f(std::move(l))//错误,需要复制构造

让我非常失望和困惑的是,它在我脸上留下了一堆错误信息。正如您已经知道的,
std::function
禁止对不可复制构造的类型进行构造。有没有具体的原因?还是标准中的疏忽?仅移动类型的构造会带来什么问题?

std::function
只能执行仅可调用的移动,但只能将自身限制为始终仅移动。它使用类型擦除来存储对象,因此它的静态行为必须表示它所存储的对象所需的最低公分母功能

这里有一个问题:C++中有很多地方,它的标准库都希望可调用的是可复制的。我所说的“lot”是指整个标准算法库。甚至是C++20概念。本质上,所有算法都被赋予了随意复制给定函数的自由;他们甚至按价值接受这些功能


只有move-only
std::function
类型不能与任何此类算法一起使用。而仅移动是
std::function
采取仅移动类型的唯一方式。

当您复制
std::function
时会发生什么?
std::function
必须是可复制的,否则您将失去该类型的巨大好处。有条件地删除复制构造函数(从而启用仅移动对象)不起作用,因为
std::function
依赖类型擦除。只有
std::function
的构造函数才能知道类型是否可复制。但是这些信息已经在类范围中丢失了。这是否回答了您的问题?但是为什么OP的代码中需要复制可构造性呢?我可以理解,如果调用
std::function
的复制构造函数,它将不会编译。但是,
std::function
的构造函数应该。@DanielLangr:这是我的第二句话:“它使用类型擦除来存储对象,所以它的静态行为必须表示它所存储的对象所需的最低公分母功能。”如果它对类型所需的最低公分母是“仅移动”,然后
std::function
本身必须仅移动。这就是类型擦除的工作原理。谢谢你的澄清。我在其中创建了一个简化的
函数。当
函数
的复制构造函数不涉及任何地方时,我首先认为不需要编译
派生::克隆
。但由于
克隆
虚拟的
,因此即使不使用它,似乎也必须对其进行编译。这个解释对吗?(这有点类似于中,其中未编译
f
,但即使未使用
g
,也会编译,因为它是
virtual
)。@DanielLangr这就是类型擦除的全部要点。当我们退出已擦除容器的构造函数时,我们将丢失有关类型是可复制还是可移动构造的信息(
函数在您的示例中为
)。在这一点上,我们必须遵守已擦除容器指定的契约,因为没有办法将丢失的信息获取回来(至少在今天)。继承的使用只是一个实现细节,并不真正相关。是的,虚拟函数必须实例化,因为您可以通过基指针访问它们。