委托实现c ++,如何查找特定的类成员函数

时间:2013-11-26 20:28:12

标签: c++ c++11 std-function

我正在研究如何用c ++ 11实现简单的委托。 disconnect-method的问题,我想针对要从地图中删除的特定对象的特定功能。通过此实现,我擦除连接到特定对象实例的所有函数。我希望能够做到这样的事情:

delegate.disconnect (myobj, &MyObj::method)

而不是

delegate.disconnect (myobj)

删除myobj的所有connceted函数。

template <typename ... Params >
class Delegate {

private:    
    typedef std::function < void (Params...)> FunctionType;
    std::map < void*, std::vector < FunctionType >> m_functions;

public:
    template <typename Class>
    void connect(Class& obj, void (Class::*func) (Params...) ) 
    {
        std::function < void (Class, Params...) >  f = func;
        FunctionType fun = [&obj, f](Params... params) { f(obj, params...); };
        m_functions[&obj].push_back(fun);
    }

    template <typename Class>
    void disconnect(Class& obj) {
        m_functions.erase(&obj);
    }

    template <typename ... Args>
    void operator() (Args...args)
    {       
        for (auto& pair : m_functions) {
            for (auto& func : pair.second) {
                func(args...);
            }
        }
    }
};

2 个答案:

答案 0 :(得分:1)

std :: function仅与nullptr_t see here

相当

出于这个原因,我将使用类似于下面提供的解决方案,其中返回的对象在破坏期间使用迭代器取消映射。当然,其中一个需要一个容器,它的迭代器不会失效。可以编写各种类似的习语,并且可以尝试使其完全通用。我刚刚提供了这个想法,但(在下面这里)

由于映射迭代器在插入时没有失效,我通常会返回一个包装迭代器的对象,并在超出范围时使用迭代器取消映射:

它看起来像这样......

struct Resource{ virtual ~Resource(){} };

template <class SubjectT, class IterT>
struct Unmapper : Resource
{
  typedef void (SubjectT::*UnmapFunc)( IterT );

  Unmapper(
    std::shared_ptr<SubjectT> subject, UnmapFunc unmap, IterT ref )
  : subject_( subject ), ref_( ref ), unmap_( unmap )
  {
  }

  ~Unmapper()
  {
    std::shared_ptr<SubjectT> subject = subject_.lock();
    if( subject ){ ((*subject).*unmap_)( ref_ ); }
  }
  private:
    std::weak_ptr<SubjectT> subject_;
    IterT ref_;
    UnmapFunc unmap_;

};

template <class SubjectT, class IterT>
std::unique_ptr<Resource> makeUnmapper( std::shared_ptr<SubjectT> subject,
  void (SubjectT::*unmapFunc)( IterT ), IterT ref )
{
  return std::unique_ptr<Resource>( 
    new Unmapper<SubjectT, IterT>( subject, unmapFunc, ref ) );
}

......和......

//Could generalise by using variadic templates, yes...
class Subject : public std::enable_shared_from_this
{
  public:
    typedef std::function<void()> my_function;
    std::unique_ptr<Resource> subscribe( int id, my_function func )
    {
      //psuedo code...
      my_map::iterator pos = myMap_.insert( id, func );
      if( pos.second )
      {
        return makeUnmapper( shared_from_this(), &Subject::unmap, pos );
      }
      else throw already_subscribed();  
    }

  private:
    //etc... declare map etc...
    void unmap( my_map::iterator pos ){ myMap_.erase( pos ); }
};

注意: 我没有编译这个。我可能错过了一个动作,但我对此表示怀疑,因为unique_ptr总是rvalues。

答案 1 :(得分:0)

我找到了一种方法来散列成员函数,这是我需要的,所以我在这里回答我自己的问题:

template <typename Class>
size_t getHash(void (Class::*func) (Params...)) {
    const char *ptrptr = static_cast<const char*>(static_cast<const void*>(&func));
    int size = sizeof (func);
    std::string str_rep(ptrptr, size);
    std::hash<std::string> strHasher;
    return strHasher(str_rep);
}

用法现在很简单:

delegate.disconnect(&MyClass::MyFunc);

参考: How to hash and compare a pointer-to-member-function?