如何解决在什么情况下我必须使用std :: function?
我很难想象std::function
的真实用例无法被模板覆盖。每当我考虑使用std::function
时,我都会找到一种避免它的方法:
// implementation using std::function
void forEach(std::array<int,100> &data,const std::function<void(int&)> &f)
{
for (size_t i = 0; i < 100; ++i) {
f(data[i]);
}
}
// implementation using any functor which takes an int&
template <typename Callable>
void forEach(std::array<int,const Callable &f)
requires std::is_invocable_v<Callable,int&>
{
for (size_t i = 0; i < 100; ++i) {
f(data[i]);
}
}
诚然,使用std::function
的实现要短一些,但是由于类型擦除,它每次迭代都需要一个虚拟调用,并且编译器无法很好地对其进行优化。 (Live example)
那么std::function
的真正用例是什么,而不能使用模板呢?完全不需要std::function
吗?
解决方法
std::function
类型可擦除可调用类型,并可以对其进行同质处理。
例如,您可以有一个回调向量:
std::vector<std::function<int(std::string)>> callbacks;
,
以类中的虚拟方法为例。带有模板参数的虚拟方法是不允许的
class A : public Base {
public:
virtual void forEach(std::function<void(int&)> f);
}
,
function
提供的是类型擦除。在模板不合适甚至不可行的地方,类型擦除非常有用。类型擦除的典型用例是代码中有两个地方,即A和B。A需要向B发送消息。但是这种发送需要通过中间代码C进行。
C不能作为模板,因为C是用于存储或传递某些数据的通用介质。考虑一个信号和时隙系统。插槽的特定用法要求特定的可调用签名,这是信号发送器发送的。现在,根据您提供的呼叫对象的类型,创建插槽可以作为模板。但是,那么您就无法在单个插槽中具有多个回调,因为您需要能够存储它们的数组以按顺序调用。您不能存储对象的异构容器。因此,插槽需要以一种可以调用它的方式存储可调用对象,而不必绑定到特定的可调用对象类型。签名是指定的,不是实际可调用的。
输入擦除类型。
std::function
和类似的类型擦除类型适用于您的界面和内部实现 由于某种原因而不能作为模板的情况。可能是因为您需要存储具有共享接口的可能不同类型的对象的容器。这可能是因为中间代码建立在实际上无法处理模板的C样式的接口上。或者,也许您不想将包含泛型可调用对象的类型设置为模板,以便用户可以提供任意可调用对象(模板不是免费的,尤其是在编译时)。或其他各种因素。
但是一般的共同点是对象提供者和对象用户之间的中间代码不能为模板。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。