C++ 将void*转换为std::function<;void()>;
将具有不同参数的函数指针存储在空指针向量中C++ 将void*转换为std::function<;void()>;,c++,function,pointers,casting,std,C++,Function,Pointers,Casting,Std,将具有不同参数的函数指针存储在空指针向量中 unordered_map<string, vector<void*> > List; template <typename T> void Listen(string Name, function<void(T)> Function) { List[Name].push_back(&Function); } 但我得到了一个编译器错误,它读取错误C2064:term不会对文件中包含1个
unordered_map<string, vector<void*> > List;
template <typename T>
void Listen(string Name, function<void(T)> Function)
{
List[Name].push_back(&Function);
}
但我得到了一个编译器错误,它读取错误C2064:term不会对文件中包含1个参数的函数求值…\vc\include\xrefwrap 431 1
我做错了什么?首先,您获取了一个参数的地址,如下所示:
List[Name].push_back(&Function);
然后尝试将迭代器对象转换为std::function
对象:
(function<void(T)>)i)
#包括
#包括
#包括
#包括
#包括
模板结构块演绎{typedef T type;};
结构BaseCallback{
虚拟~BaseCallback();
模板
void DoCall(typename blockreduction::type&&t)const;
};
模板
结构回调:BaseCallback
{
std::函数func;
回调函数(std::function const&f):func(f){}
};
模板
void BaseCallback::DoCall(typename blockdeclusion::type&&t)const{
断言(动态_cast(this));
static_cast(this).func(std::forward(t));
}
typedef std::unique_ptr upCallback;
模板
upCallback make_回调(std::function const&f){
返回上回调(新回调(f));
}
结构侦听器{
std::无序映射List;
模板
void Listen(std::string Name,std::function f){
列表[名称]。推回(生成回调(f));
}
模板
无效火灾(标准::字符串名称、类型名称、类型和类型){
自动回调=List.find(Name);
if(callbacks==List.end())返回;
对于(自动it=callbacks->second.begin();it!=callbacks->second.end();++it){
if(it+1=callbacks->second.end())
{
(**it.DoCall(std::forward(t));
}否则{
(**it.DoCall(t);
}
}
}
};
。。。或者类似的
这将在映射中存储std::function
的一个副本,并以一般方式包装。内存通过唯一\u ptr
处理。我小心地在类型必须与安装侦听器时使用的类型完全相同的地方阻止了类型推断(此时的自动类型推断相当脆弱)
在debug中,如果违反Nametype映射,将导致断言失败
需要为空回调做一些额外的工作。只需编写一个DoCall
,将BaseCallback
强制转换为Callback
,专门化Callback
为空函数
包装,专门化在空函数
上生成回调
,并编写一个激发(字符串)
调用裸DoCall
的侦听器的方法
或者创建一个struct Empty
并使用lambdas将空函数包装到函数中,这将涉及更少的代码,但在运行时会更慢。您正在推送参数的地址。为什么不在列表中保存std::function
?@Lol4t0。遗憾的是,我不能在同一个列表中保存不同的类型。例如函数
,函数
和函数
都是不同的类型。@chill。既然它是一个空指针向量,那有什么错呢?是的,但是在调用函数时你也无法确定函数的类型。&
在Listen
函数的参数上使用的是什么?我能以某种方式避免吗?这是为了确保使用左值调用函数,即使用具有地址的对象。仍然需要确保地址在向量/映射中保持有效。我喜欢这样,但我需要一些时间来真正理解您所做的一切。请注意,std::forward
垃圾可能是错误的——我仍在尝试摸索。我可能不应该包括它,只是做了一些类型t
的冗余副本<代码>块扣除
仅用于阻止自动功能类型扣除(因为Fire
采用的T
必须与T
侦听
采用的类型或未定义的行为结果完全匹配)。BaseCallback
确实存在是为了拥有一个虚拟dtor(因此调用了它的子类dtor),而DoCall
方法只是将危险的static\u cast
放入类中<代码>唯一\u ptr
管理生命周期。
(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);
}
}
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 );
}
}
}
};