将void *转换为std :: function <void()> </void()>

时间:2012-12-01 20:28:42

标签: c++ function pointers casting std

存储函数指针是否在void指针的向量中具有不同的参数。

unordered_map<string, vector<void*> > List;

template <typename T>
void Listen(string Name, function<void(T)> Function)
{
    List[Name].push_back(&Function);
}

然后我想打电话给他们,假设TFire的{​​{1}}类型相同。

Listen

但是我收到一个编译错误,其中显示template <typename T> void Fire(string Name, T Data) { auto Functions = List[Name]; for (auto i = Functions.begin(); i != Functions.end(); ++i) { (function<void(T)>)i)(Data); } }

我做错了什么?

2 个答案:

答案 0 :(得分:2)

首先,您将获取参数的地址:

List[Name].push_back(&Function);

然后你试图将迭代器对象转换为std::function对象:

(function<void(T)>)i)

你想做的事情可以做到,就像这样,虽然它并不漂亮,但温和地说:

unordered_map<string, vector<void*> > List;

template <typename T>
void Listen(string Name, function<void(T)> &Function)
{
    List[Name].push_back(&Function);
}

template <typename T>
void Fire(string Name, T Data)
{
    auto Functions = List[Name];

    for (auto i = Functions.begin(); i != Functions.end(); ++i)
    {
      function<void(T)> *ptr = *i;

      (*ptr) (Data);
    }
}

它可以在很多方面中断,例如你无法控制在Listen中使用正确的参数调用在Fire中以某个名称注册的函数 - 考虑调用{{1}然后做Listen<int> ("foo", f);

另一种方法 - 只需传递回调闭包:

Fire<double> ("foo", 3.14);

答案 1 :(得分:1)

#include <functional>
#include <unordered_map>
#include <memory>
#include <string>
#include <vector>

template<typename T> struct BlockDeduction{typedef T type;};
struct BaseCallback {
  virtual ~BaseCallback();
  template<typename T>
  void DoCall( typename BlockDeduction<T>::type&& t ) const;
};
template<typename T>
struct Callback: BaseCallback
{
  std::function<void(T)> func;
  Callback( std::function<void(T)> const& f ):func(f) {}
};


template<typename T>
void BaseCallback::DoCall( typename BlockDeduction<T>::type&& t ) const {
  Assert( dynamic_cast<Callback<T>const*>(this) );
  static_cast<Callback<T>const*>(this).func(std::forward(t));
}

typedef std::unique_ptr<BaseCallback> upCallback;
template<typename T>
upCallback make_callback( std::function<void(T)> const& f ) {
  return upCallback( new Callback<T>( f ) );
}


struct Listener {
  std::unordered_map< std::string, std::vector<upCallback>> List;
  template<typename T>
  void Listen( std::string Name, std::function<void(T)> f) {
    List[Name].push_back( make_callback(f) );
  }
  template<typename T>
  void Fire( std::string Name, typename BlockDeduction<T>::type&& t ) {
    auto callbacks = List.find(Name);
    if (callbacks == List.end()) return;
    for(auto it = callbacks->second.begin(); it != callbacks->second.end(); ++it) {
      if (it +1 = callbacks->second.end())
      {
        (**it).DoCall<T>( std::forward(t) );
      } else {
        (**it).DoCall<T>( t );
      }
    }
  }
};

......或类似的东西。

这会在地图中存储std::function的副本,一般包含在内。内存通过unique_ptr处理。我小心地阻止了类型扣除,其类型必须与您在安装Listener时完全相同(此时自动类型扣除相当脆弱)。

在调试中,如果违反Name&lt; - &gt;类型映射,则会出现断言失败。

需要为Nullary回调做一些额外的工作。只需写一个DoCall,将BaseCallback强制转换为Callback<void>,将Callback<void>专门化为一个无效的function包装器,将make_callback专门化为function Fire(string)并为Listener编写一个调用裸DoCall的{​​{1}}方法。

或创建一个struct Empty并使用lambdas在function<void(Empty)>中包含nullary函数,这将涉及稍微少的代码,但在运行时会更慢。