美文网首页
一对多回调例程

一对多回调例程

作者: Junior888 | 来源:发表于2018-08-23 23:41 被阅读0次

在C++11中,借助variadic template,实现最简单的(trivial)的一对多回调。

#include "../SignalSlot.h"
#include "../SignalSlotTrivial.h"

#include <boost/bind.hpp>

#define BOOST_TEST_MAIN
#ifdef BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#else
#include <boost/test/included/unit_test.hpp>
#endif

class String
{
 public:
  String(const char* str)
  {
    printf("String ctor this %p\n", this);
  }

  String(const String& rhs)
  {
    printf("String copy ctor this %p, rhs %p\n", this, &rhs);
  }

  String(String&& rhs)
  {
    printf("String move ctor this %p, rhs %p\n", this, &rhs);
  }
};

class Foo : boost::noncopyable
{
 public:
  void zero();
  void zeroc() const;
  void one(int);
  void oner(int&);
  void onec(int) const;
  void oneString(const String& str);
  // void oneStringRR(String&& str);
  static void szero();
  static void sone(int);
  static void soneString(const String& str);
};

void Foo::zero()
{
  printf("Foo::zero()\n");
}

void Foo::zeroc() const
{
  printf("Foo::zeroc()\n");
}

void Foo::szero()
{
  printf("Foo::szero()\n");
}

void Foo::one(int x)
{
  printf("Foo::one() x=%d\n", x);
}

void Foo::onec(int x) const
{
  printf("Foo::onec() x=%d\n", x);
}

void Foo::sone(int x)
{
  printf("Foo::sone() x=%d\n", x);
}

void Foo::oneString(const String& str)
{
  printf("Foo::oneString\n");
}

void Foo::soneString(const String& str)
{
  printf("Foo::soneString\n");
}

BOOST_AUTO_TEST_CASE(testSignalSlotTrivialZero)
{
  SignalTrivial<void()> signal;

  printf("========\n");
  signal.call();

  signal.connect(&Foo::szero);

  printf("========\n");
  signal.call();

  Foo f;
  signal.connect(boost::bind(&Foo::zero, &f));

  printf("========\n");
  signal.call();

  signal.connect(boost::bind(&Foo::one, &f, 42));

  printf("========\n");
  signal.call();

  const Foo cf;
  signal.connect(boost::bind(&Foo::zeroc, &cf));

  printf("========\n");
  signal.call();

  signal.connect(boost::bind(&Foo::onec, &cf, 128));

  printf("========\n");
  signal.call();

  printf("========\n");
  signal.call();
}

BOOST_AUTO_TEST_CASE(testSignalSlotTrivialOne)
{
  SignalTrivial<void(int)> signal;

  printf("========\n");
  signal.call(50);

  signal.connect(&Foo::sone);

  printf("========\n");
  signal.call(51);

  Foo f;
  signal.connect(boost::bind(&Foo::one, &f, _1));

  printf("========\n");
  signal.call(52);

  const Foo cf;
  signal.connect(boost::bind(&Foo::onec, &cf, _1));

  printf("========\n");
  signal.call(53);
}

BOOST_AUTO_TEST_CASE(testSignalSlotTrivialString)
{
  SignalTrivial<void(const String&)> signal;
  signal.call("hello");

  signal.connect(&Foo::soneString);

  printf("========\n");
  signal.call("hello");

  Foo f;
  signal.connect(boost::bind(&Foo::oneString, &f, _1));

  printf("========\n");
  signal.call("hello");
}

BOOST_AUTO_TEST_CASE(testSignalSlotZero)
{
  muduo::Signal<void()> signal;

  printf("==== testSignalSlotZero ====\n");
  signal.call();

  muduo::Slot s1 = signal.connect(&Foo::szero);

  printf("========\n");
  signal.call();

  Foo f;
  muduo::Slot s2 = signal.connect(boost::bind(&Foo::zero, &f));

  printf("========\n");
  signal.call();

  muduo::Slot s3 = signal.connect(boost::bind(&Foo::one, &f, 42));

  printf("========\n");
  signal.call();

  const Foo cf;
  muduo::Slot s4 = signal.connect(boost::bind(&Foo::zeroc, &cf));

  printf("========\n");
  signal.call();

  muduo::Slot s5 = signal.connect(boost::bind(&Foo::onec, &cf, 128));

  printf("========\n");
  signal.call();

  s1 = muduo::Slot();
  printf("========\n");
  signal.call();


  s4 = s3 = s2 = muduo::Slot();
  printf("========\n");
  signal.call();

}

BOOST_AUTO_TEST_CASE(testSignalSlotOne)
{
  muduo::Signal<void(int)> signal;

  printf("========\n");
  signal.call(50);

  muduo::Slot s4;
  {
  muduo::Slot s1 = signal.connect(&Foo::sone);

  printf("========\n");
  signal.call(51);

  Foo f;
  muduo::Slot s2 = signal.connect(boost::bind(&Foo::one, &f, _1));

  printf("========\n");
  signal.call(52);

  const Foo cf;
  muduo::Slot s3 = signal.connect(boost::bind(&Foo::onec, &cf, _1));

  printf("========\n");
  signal.call(53);

  s4 = s3;
  }

  printf("========\n");
  signal.call(54);
}

BOOST_AUTO_TEST_CASE(testSignalSlotLife)
{
  muduo::Slot s1;

  {
  muduo::Signal<void()> signal;
  s1 = signal.connect(&Foo::szero);

  printf("========\n");
  signal.call();

  Foo f;
  boost::function<void()> func = boost::bind(&Foo::zero, &f);

  s1 = signal.connect(func);

  printf("========\n");
  signal.call();
  }

}
#ifndef MUDUO_BASE_SIGNALSLOT_H
#define MUDUO_BASE_SIGNALSLOT_H

#include "Mutex.h"

#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>

#include <vector>

namespace muduo
{

namespace detail
{

template<typename Callback>
struct SlotImpl;

template<typename Callback>
struct SignalImpl : boost::noncopyable
{
  typedef std::vector<boost::weak_ptr<SlotImpl<Callback> > > SlotList;

  SignalImpl()
    : slots_(new SlotList)
  {
  }

  void copyOnWrite()
  {
    mutex_.assertLocked();
    if (!slots_.unique())
    {
      slots_.reset(new SlotList(*slots_));
    }
    assert(slots_.unique());
  }

  void clean()
  {
    MutexLockGuard lock(mutex_);
    copyOnWrite();
    SlotList& list(*slots_);
    typename SlotList::iterator it(list.begin());
    while (it != list.end())
    {
      if (it->expired())
      {
        it = list.erase(it);
      }
      else
      {
        ++it;
      }
    }
  }

  MutexLock mutex_;
  boost::shared_ptr<SlotList> slots_;
};

template<typename Callback>
struct SlotImpl : boost::noncopyable
{
  typedef SignalImpl<Callback> Data;
  SlotImpl(const boost::shared_ptr<Data>& data, Callback&& cb)
    : data_(data), cb_(cb), tie_(), tied_(false)
  {
  }

  SlotImpl(const boost::shared_ptr<Data>& data, Callback&& cb,
           const boost::shared_ptr<void>& tie)
    : data_(data), cb_(cb), tie_(tie), tied_(true)
  {
  }

  ~SlotImpl()
  {
    boost::shared_ptr<Data> data(data_.lock());
    if (data)
    {
      data->clean();
    }
  }

  boost::weak_ptr<Data> data_;
  Callback cb_;
  boost::weak_ptr<void> tie_;
  bool tied_;
};

}

/// This is the handle for a slot
///
/// The slot will remain connected to the signal fot the life time of the
/// returned Slot object (and its copies).
typedef boost::shared_ptr<void> Slot;

template<typename Signature>
class Signal;

template <typename RET, typename... ARGS>
class Signal<RET(ARGS...)> : boost::noncopyable
{
 public:
  typedef std::function<void (ARGS...)> Callback;
  typedef detail::SignalImpl<Callback> SignalImpl;
  typedef detail::SlotImpl<Callback> SlotImpl;

  Signal()
    : impl_(new SignalImpl)
  {
  }

  ~Signal()
  {
  }

  Slot connect(Callback&& func)
  {
    boost::shared_ptr<SlotImpl> slotImpl(
        new SlotImpl(impl_, std::forward<Callback>(func)));
    add(slotImpl);
    return slotImpl;
  }

  Slot connect(Callback&& func, const boost::shared_ptr<void>& tie)
  {
    boost::shared_ptr<SlotImpl> slotImpl(new SlotImpl(impl_, func, tie));
    add(slotImpl);
    return slotImpl;
  }

  void call(ARGS&&... args)
  {
    SignalImpl& impl(*impl_);
    boost::shared_ptr<typename SignalImpl::SlotList> slots;
    {
      MutexLockGuard lock(impl.mutex_);
      slots = impl.slots_;
    }
    typename SignalImpl::SlotList& s(*slots);
    for (typename SignalImpl::SlotList::const_iterator it = s.begin(); it != s.end(); ++it)
    {
      boost::shared_ptr<SlotImpl> slotImpl = it->lock();
      if (slotImpl)
      {
        boost::shared_ptr<void> guard;
        if (slotImpl->tied_)
        {
          guard = slotImpl->tie_.lock();
          if (guard)
          {
            slotImpl->cb_(args...);
          }
        }
        else
        {
          slotImpl->cb_(args...);
        }
      }
    }
  }

 private:

  void add(const boost::shared_ptr<SlotImpl>& slot)
  {
    SignalImpl& impl(*impl_);
    {
      MutexLockGuard lock(impl.mutex_);
      impl.copyOnWrite();
      impl.slots_->push_back(slot);
    }
  }

  const boost::shared_ptr<SignalImpl> impl_;
};

}

#endif // MUDUO_BASE_SIGNALSLOT_H
#ifndef MUDUO_BASE_SIGNALSLOTTRIVIAL_H
#define MUDUO_BASE_SIGNALSLOTTRIVIAL_H

#include <memory>
#include <vector>

template<typename Signature>
class SignalTrivial;

template <typename RET, typename... ARGS>
class SignalTrivial<RET(ARGS...)>
{
 public:
  typedef std::function<void (ARGS...)> Functor;

  void connect(Functor&& func)
  {
    functors_.push_back(std::forward<Functor>(func));
  }

  void call(ARGS&&... args)
  {
    // gcc 4.6 supports
    //for (const Functor& f: functors_)
    typename std::vector<Functor>::iterator it = functors_.begin();
    for (; it != functors_.end(); ++it)
    {
      (*it)(args...);
    }
  }

 private:
  std::vector<Functor> functors_;
};

#endif // MUDUO_BASE_SIGNALSLOTTRIVIAL_H

boost::bind

相关文章

  • 一对多回调例程

    在C++11中,借助variadic template,实现最简单的(trivial)的一对多回调。 boost:...

  • iOS Block一对多回调的实现

    前言 我们都知道,回调的方案有Block、代理、通知。要想实现一对多就要用通知。而且很方便的在多个地方进行回调,实...

  • 面试题 - iOS中如何用Block实现一对多回调

    之前面试的时候被面试官问到 “如何使用block实现一对多回调”,那会儿只知道回调分两种,第一种是一对一的,就是常...

  • Kotlin 简化多回调函数

    Kotlin 简化多回调函数 这里只是简单的例子,并没有实际意义,可以通过这个方法改造Android的TextWa...

  • express-session的常用参数

    Session Store Implementation session store的诸多回调,session s...

  • jQuery回调函数

    1.引言 利用回调函数来当参数,会极大的提高程序的灵活性。对回调函数很陌生,研究了一下给的示例程序,感觉对回调函数...

  • JS回调函数和回调地狱

    什么是回调函数? 回调函数是作为参数传递给另一个函数的函数,然后在外部函数内调用该函数以完成某种例程或操作。一个回...

  • Table View 中图片加载逻辑的优化

    当 scroll view 开始滚动时,scroll view 的 delegate 会不断的收到很多回调消息,这...

  • ES8(一) —— async&await

    目录 async和普通函数的区别 await async/await处理多回调异步 async和await必须配合...

  • 例程

    每天的进展简单总结,以后方便回忆回顾,也增加进展感和成就感,适当补写以前可以回忆起来部分,包括所有小时候的事情,以...

网友评论

      本文标题:一对多回调例程

      本文链接:https://www.haomeiwen.com/subject/bfyviftx.html