如何投射类型擦除的 std::function?

How to cast type-erased std::function?

本文关键字:function std 何投射 类型 擦除      更新时间:2023-10-16

我需要实现可观察的对象,当某些值发生变化时通知观察者。 一些观察者不需要知道该值。某些观察点已被类型擦除,但具有反射元数据来解释 void* 和读取数据。一些观察者使用类型安全的接口。

为了支持各种观察者,我将所有内容存储在std::function<void(void*)>中。 但这需要额外的间接层(额外的std::function(才能从类型擦除转换为类型安全的界面:

template<typename T> 
struct observable {
std::vector<std::function<void(void *)>> funcs;
void add_observer(std::function<void(void *)> &&f) 
{ 
funcs.emplace_back(f); 
}
void add_observer(std::function<void(T&)> &&f)
{
// extra layer of indirection
add_observer([f](void * val)
{
f(*reinterpret_cast<T*>(val));
});
}
void notify(T& new_val) 
{
for (const& f : funcs) { f(&new_val); }
}
};

是否有可能将function<void(void*)>转换为function<void(T&)>以避免这种低效率?

将可调用的观察者直接存储,而不是作为std::function存储。然后,您可以避免双重std::function间接(假设调用方尚未提供std::function作为add_observer的参数(:

template<typename F>
void add_observer(F &&f)
{
funcs.emplace_back([f=std::forward<F>(f)](void * val) mutable
{
f(*static_cast<T*>(val));
});
}
请注意,如果可调用对象

具有较大的状态,则将可调用对象转发到 lambda 中可能会更有效,并且还要注意,static_cast足以将void*转换为另一个对象指针类型。


您要求的std::function混凝土浇注不存在。它要求std::functionvoid*的预期语义做出根本不明显的假设 ->T&

No.

有些解决方案不涉及性病功能,但它们是疯狂的。