C++ 事件类需要更新
我有一个事件类,它是用半个C和半个C++11编写的 它目前不适用于lambdas或C++ 事件类需要更新,c++,templates,c++17,variadic-templates,std-function,C++,Templates,C++17,Variadic Templates,Std Function,我有一个事件类,它是用半个C和半个C++11编写的 它目前不适用于lambdas或std::functions,仅适用于自由函数或成员函数 它很难正确使用(我从来没有使用过简单的Subscribe方法来编译),而且void*和原始函数指针的使用非常糟糕 我想用C++17和适当的可变模板类型来更新它,使用lambdas和std::function,希望只有一组公共的订阅/取消订阅方法可以处理我提供的任何东西 事件hpp #pragma once #include <vector>
std::functions
,仅适用于自由函数或成员函数
它很难正确使用(我从来没有使用过简单的Subscribe方法来编译),而且void*
和原始函数指针的使用非常糟糕
我想用C++17和适当的可变模板类型来更新它,使用lambdas和std::function
,希望只有一组公共的订阅/取消订阅方法可以处理我提供的任何东西
事件hpp
#pragma once
#include <vector>
template <typename... ARGS>
class Event {
public:
struct event_sub_t;
using cb_t = void(*)(event_sub_t*, ARGS...);
using cb_with_arg_t = void(*)(void*, ARGS...);
struct event_sub_t {
cb_t cb;
void *secondary_cb;
void *user_arg;
};
Event() = default;
~Event() = default;
void Subscribe(void *user_arg, cb_with_arg_t cb) {
event_sub_t sub;
sub.cb = FunctionWithArgumentCallback;
sub.secondary_cb = cb;
sub.user_arg = user_arg;
subscriptions.push_back(sub);
}
void Unsubscribe(void *user_arg, void* cb) {
subscriptions.erase(std::remove_if(std::begin(subscriptions),
std::end(subscriptions),
[&cb, &user_arg](const event_sub_t& sub) {
return (sub.secondary_cb == cb) && (sub.user_arg == user_arg);
}),
std::end(subscriptions));
}
void Unsubscribe_by_argument(void *user_arg) {
subscriptions.erase(std::remove_if(std::begin(subscriptions),
std::end(subscriptions),
[&user_arg](const event_sub_t& sub) {
return sub.user_arg == user_arg;
}),
std::end(subscriptions));
}
template <typename T>
void Subscribe_method(T *obj, void (T::*mcb)(ARGS...)) {
event_sub_t sub;
sub.cb = MethodCallback<T, decltype(mcb)>;
sub.secondary_cb = *(void**)(&mcb);
sub.user_arg = obj;
subscriptions.push_back(sub);
}
template <typename T>
void Unsubscribe_method(T *obj, void (T::*mcb)(ARGS...)) {
Unsubscribe(obj, *(void**)&mcb);
}
template <typename T>
void Unsubscribe_object(T *obj) {
Unsubscribe_by_argument(obj);
}
void Trigger(ARGS... args) {
for(auto& sub : subscriptions) {
sub.cb(&sub, std::forward<ARGS>(args)...);
}
}
private:
std::vector<event_sub_t> subscriptions;
static void FunctionWithArgumentCallback(event_sub_t *sub, ARGS... args);
template <typename T, typename MCB>
static void MethodCallback(event_sub_t *sub, ARGS... args);
};
template <typename ...ARGS>
void Event<ARGS...>::FunctionWithArgumentCallback(event_sub_t *sub, ARGS... args) {
cb_with_arg_t cb = (cb_with_arg_t)(sub->secondary_cb);
cb(sub->user_arg, std::forward<ARGS>(args)...);
}
template <typename ...ARGS>
template <typename T, typename MCB>
void Event<ARGS...>::MethodCallback(event_sub_t *sub, ARGS... args) {
MCB mcb = *(MCB*)&(sub->secondary_cb);
T *obj = (T*)(sub->user_arg);
(obj->*mcb)(std::forward<ARGS>(args)...);
}
不知道你需要什么 但在我看来,您需要
std::bind()
无论如何。。。如果在Subscribe()
中传递单个可调用函数的参数,那么在我看来,Event
不再需要作为模板类,而std::function
的std::vector
如下所示
private:
std::vector<std::function<void()>> subsV;
注意,对于一个简单的可调用(而不是非静态类/结构方法),您必须首先通过可调用函数调用它,然后通过参数调用它
auto i1 = e.Subscribe(
[](int, long){ std::cout << "l1" << std::endl; }, 0, 1l);
对于unsubscribe()
我建议传递订阅的索引(由Subscribe()返回)
而触发器()
void Trigger ()
{
for ( auto & sub : subsV )
if ( sub )
sub();
}
下面是一个完整的编译示例(也适用于C++11)
#包括
#包括
#包括
班级活动
{
私人:
std::向量subsV;
公众:
Event()=默认值;
~Event()=默认值;
样板
std::size\u t Subscribe(F const&F,Args const&as)
{
subsV.emplace_uback(std::bind(f,as…);
返回SUSV.size()-1u;
}
无效取消订阅(标准::大小\u t idx)
{subsV.at(idx)=nullptr;}
无效触发器()
{
用于(自动和子:SUSV)
如有(附属)
sub();
}
};
结构foo
{
void func(标准::字符串常量(&s)
{std::cout对我来说不清楚:在C++17中,您希望Subscribe()
同时接收Args…
参数,并且Trigger()
完全不接收任何参数(使用Subscribe()
传递的参数调用已注册的可调用函数),还是希望Trigger()
receiveArgs…
传递给可调用函数的参数?@max66我非常希望subscribe
的工作方式与std::thread
的构造函数类似,我可以给它一个成员函数、自由函数或lambda及其参数,它只知道调用什么和如何调用它。
template <typename F, typename ... Args>
std::size_t Subscribe (F const & f, Args const & ... as)
{
subsV.emplace_back(std::bind(f, as...));
return subsV.size() - 1u;
}
auto i1 = e.Subscribe(
[](int, long){ std::cout << "l1" << std::endl; }, 0, 1l);
foo f;
// ...............................V works with objects
auto i2 = e.Subscribe(&foo::func, f, "string 1");
auto i3 = e.Subscribe(&foo::funv, &f, "string 2");
// ...............................^^ and works with pointers
void Unsubscribe (std::size_t idx)
{ subsV.at(idx) = nullptr; }
void Trigger ()
{
for ( auto & sub : subsV )
if ( sub )
sub();
}
#include <vector>
#include <iostream>
#include <functional>
class Event
{
private:
std::vector<std::function<void()>> subsV;
public:
Event() = default;
~Event() = default;
template <typename F, typename ... Args>
std::size_t Subscribe (F const & f, Args const & ... as)
{
subsV.emplace_back(std::bind(f, as...));
return subsV.size() - 1u;
}
void Unsubscribe (std::size_t idx)
{ subsV.at(idx) = nullptr; }
void Trigger ()
{
for ( auto & sub : subsV )
if ( sub )
sub();
}
};
struct foo
{
void func (std::string const & s)
{ std::cout << "foo::func(): " << s << std::endl; }
};
int main()
{
Event e;
foo f;
auto i1 = e.Subscribe(
[](int, long){ std::cout << "l1" << std::endl; }, 0, 1l);
auto i2 = e.Subscribe(&foo::func, f, "string 1");
auto i3 = e.Subscribe(&foo::func, &f, "string 2");
e.Trigger();
e.Unsubscribe(i2);
e.Trigger();
e.Unsubscribe(i1);
e.Trigger();
e.Unsubscribe(i3);
e.Trigger();
}