[英]Convert void* to std::function<void()>
Is store function pointers with different parameters in a vector of void pointers. 存储函数指针是否在void指针的向量中具有不同的参数。
unordered_map<string, vector<void*> > List;
template <typename T>
void Listen(string Name, function<void(T)> Function)
{
List[Name].push_back(&Function);
}
Then I want to call them, assuming that T
is the same type for Fire
as used for the Listen
. 然后我想调用它们,假设
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);
}
}
But I get a compiler error which reads error C2064: term does not evaluate to a function taking 1 arguments in file ...\\vc\\include\\xrefwrap 431 1
. 但是我得到一个编译器错误,它读取
error C2064: term does not evaluate to a function taking 1 arguments in file ...\\vc\\include\\xrefwrap 431 1
。
What am I doing wrong? 我究竟做错了什么?
For one, you're taking the address of a parameter, here: 首先,您将获取参数的地址,此处:
List[Name].push_back(&Function);
Then you're trying to convert an iterator object to a std::function
object here: 然后你试图在这里将迭代器对象转换为
std::function
对象:
(function<void(T)>)i)
What you trying to do can be done, like this, although it's not pretty, to put it mildly: 你可以做的就是这样,虽然它并不漂亮,但温和地说:
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);
}
}
It can break in lot of ways, for example you have no control that the function, registered under some name in Listen
is called with the correct argument in Fire
- consider calling Listen<int> ("foo", f);
它可以在很多方面突破,例如,你无法控制的功能,在某些名义登记在
Listen
被称为在正确的说法Fire
-要打电话Listen<int> ("foo", f);
and then doing Fire<double> ("foo", 3.14);
然后做
Fire<double> ("foo", 3.14);
Another approach - just pass closures for callbacks: 另一种方法 - 只需传递闭包回调:
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 );
}
}
}
};
... or something like that. ... 或类似的东西。
This stores a copy of the std::function
in the map, wrapped up generically. 这将
std::function
的副本存储在地图中,一般包含在内。 Memory is handled via a unique_ptr
. 内存通过
unique_ptr
处理。 I carefully blocked type deduction at points where the type must be exactly what you used when you installed the Listener
(automatic type deduction at that point is rather fragile). 我小心地在类型必须与您在安装
Listener
时使用的类型一致时阻止了类型推导(此时自动类型推断相当脆弱)。
In debug, you'll get an assertion failure if you violate the Name<->type mapping. 在调试中,如果违反Name < - >类型映射,则会出现断言失败。
Some extra work needs to be done for nullary callbacks. 需要为Nullary回调做一些额外的工作。 Just write a
DoCall
that casts BaseCallback
to Callback<void>
, specialize Callback<void>
to be a nullary function
wrapper, specialize make_callback
on nullary function
, and write a Fire(string)
method for Listener
that calls the bare DoCall
. 只写一个
DoCall
该投射BaseCallback
到Callback<void>
,专门Callback<void>
是一个无参function
包装,专门make_callback
上无参function
,并写一个Fire(string)
用于方法Listener
调用裸DoCall
。
Or create a struct Empty
and use lambdas to wrap nullary functions in function<void(Empty)>
, which would involve slightly less code, but would be slower at run-time. 或者创建一个
struct Empty
并使用lambdas在function<void(Empty)>
包含nullary函数,这将涉及稍微少的代码,但在运行时会更慢。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.