Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 事件类需要更新_C++_Templates_C++17_Variadic Templates_Std Function - Fatal编程技术网

C++ 事件类需要更新

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>

我有一个事件类,它是用半个C和半个C++11编写的

它目前不适用于lambdas或
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()
receive
Args…
传递给可调用函数的参数?@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();
 }