C++ 11观察者模式(信号,插槽,事件,更改广播/侦听器,或任何您想要调用的模式)

lea*_*vst 34 c++ boost signals observer-pattern c++11

随着C++ 11中所做的更改(例如包含std::bind),是否有一种推荐的方法来实现一个简单的单线程观察者模式,而不依赖于核心语言或标准库(如boost::signal)之外的任何东西?

编辑

如果有人可以发布一些代码,显示如何boost::signal使用新的语言功能减少依赖,那仍然非常有用.

xto*_*ofl 28

我认为这样bind可以更容易地创建插槽(cfr.'首选'语法与'可移植'语法 - 这一切都将消失).然而,观察员管理层并没有变得那么复杂.

但是作为@R.Martinho Fernandes提到:std::vector<std::function< r(a1) > >现在很容易创建一个没有(人工)"纯虚拟"接口类的麻烦.


根据要求:关于连接管理的想法 - 可能充满了错误,但你会得到这个想法:

// note that the Func parameter is something
// like std::function< void(int,int) > or whatever, greatly simplified
// by the C++11 standard
template<typename Func>
struct signal {
  typedef int Key; // 
  Key nextKey;
  std::map<Key,Func> connections;

  // note that connection management is the same in C++03 or C++11
  // (until a better idea arises)
  template<typename FuncLike>
  Key connect( FuncLike f ) {
     Key k=nextKey++;
     connections[k]=f;
     return k;
  }

  void disconnect(Key k){
     connections.erase(k);
  }

  // note: variadic template syntax to be reviewed 
  // (not the main focus of this post)
  template<typename Args...>
  typename Func::return_value call(Args... args){
     // supposing no subcription changes within call:
     for(auto &connection: connections){
        (*connection.second)(std::forward(...args));
     }
  }
};
Run Code Online (Sandbox Code Playgroud)

用法:

signal<function<void(int,int)>> xychanged;

void dump(int x, int y) { cout << x << ", " << y << endl; }

struct XY { int x, y; } xy;

auto dumpkey=xychanged.connect(dump);
auto lambdakey=xychanged.connect([&xy](int x, int y){ xy.x=x; xy.y=y; });

xychanged.call(1,2);
Run Code Online (Sandbox Code Playgroud)

  • Listener/Observer有两个部分 - 如何发送消息(`std :: function`可以正常工作),以及如何在不再想要听到消息后分离.第二部分有点令人头疼. (3认同)
  • @BЈовић:我选择`map`可以在断开连接时查找`connection`.如果您可以使用`list`提供类似的功能,请继续. (2认同)
  • 为什么不返回一个连接对象,这样你就可以在它上面调用 disconnect() 呢?它很容易实现:只需在信号中使用 shared_ptr 并在连接代理中使用weak_ptr。这样,连接中的 disconnect() 可以检查其连接是否仍然有效(例如活动)。您也可以通过这种方式轻松支持范围连接(只需在 scoped_connection 的析构函数中调用 disconnect() )。也许我完全错了:) (2认同)