簡體   English   中英

將void *轉換為std :: function <void()>

[英]Convert void* to std::function<void()>

存儲函數指針是否在void指針的向量中具有不同的參數。

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

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

然后我想調用它們,假設T與用於Listen Fire類型相同。

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);
    }
}

但是我得到一個編譯器錯誤,它讀取error C2064: term does not evaluate to a function taking 1 arguments in file ...\\vc\\include\\xrefwrap 431 1

我究竟做錯了什么?

首先,您將獲取參數的地址,此處:

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 -要打電話Listen<int> ("foo", f); 然后做Fire<double> ("foo", 3.14);

另一種方法 - 只需傳遞閉包回調:

unordered_map<string, std::vector<function<void()> > > List;

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

void Fire(string Name)
{
    auto Functions = List[Name];

    for (auto i = Functions.begin(); i != Functions.end(); ++i)
      (*i) ();
}
#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 < - >類型映射,則會出現斷言失敗。

需要為Nullary回調做一些額外的工作。 只寫一個DoCall該投射BaseCallbackCallback<void> ,專門Callback<void>是一個無參function包裝,專門make_callback上無參function ,並寫一個Fire(string)用於方法Listener調用裸DoCall

或者創建一個struct Empty並使用lambdas在function<void(Empty)>包含nullary函數,這將涉及稍微少的代碼,但在運行時會更慢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM