[英]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
该投射BaseCallback
到Callback<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.