首页 > 解决方案 > 如何转换类型擦除的 std::function?

问题描述

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

为了支持各种观察者,我将所有内容都存储在std::function<void(void*)>. 但这需要额外的间接层(extra 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&)>以避免这种低效率?

标签: c++

解决方案


将可调用的观察者直接存储而不是 as std::function。然后你可以避免双重std::function间接(假设调用者还没有提供std::functionas 参数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&根本不明显的假设。


推荐阅读