2017-09-26 39 views
-1

好吧,我已经有这个作为一个工作的例子,但我只是想清理它。使用函数调用内部的绑定

目前我有一个订阅风格的事件系统与回调例程。

我在将常规函数和类成员函数添加到存储变量中没有问题。

但id喜欢通过重载我的Event.subscribe方法来清理它。

目前,它做一些事情,像这样:

template <class T> 
class EventObject 
{ 
public: 
    void subscribe(const T& arg) 
    { 
     this->events.push_back(arg); 
    } 
std::vector<T> events; 
} 

,然后在我的主要的使用,像这样:

void someCallback(const std::string& line) 
{ 
    cout <<line; 
} 

typedef std::function<void(const std::string& line)> onMessageCallbackFunction; 
EventObject<onMessageCallbackFunction> messageCallback; 

messageCallback.subscribe(someCallback); 

现在泡菜挺身而出,当我使用一个类的成员函数。我讨厌在传递它之前必须内在地绑定这个函数。它使代码看起来很脏。

例如:

class B 
{ 
    void callbk(const std::string& line) {} 
}; 

B b; 
using std::placeholders::_1; 
onMessageCallbackFunction memfunc = std::bind(&B::callbk, b, _1); 
messageCallback.subscribe(memfunc); 

现在推倒它的工作原理,但它看起来糟糕。什么是语法,所以我可以只是瓶胚:

messageCallback.subscribe(&B::callbk, b); 

试过几个,但我似乎无法得到它只是正确的。

它是什么并不:

template <class J> 
void subscribe(J::T cls,T& t); //Nope. 
void subscribe(J&& cls,T& t); //Nope. 

超近距:(THX TOBI)

template< class J, class... Args > 
void subscribe(void(J::*funct)(Args), J& inst) { 
    using std::placeholders::_1; 
    subscribe(std::bind(funct, inst, _1)); 
} 

现在只需要一般的参数列表。

+1

不知道,但我想我宁愿lambdas绑定 – user463035818

+0

你可以看到它是如何实现在std :: thread ctor(3) - http://en.cppreference.com/w/cpp/thread/thread/thread-它不是微不足道的,所以你更好地使用'std :: function' – Slava

+0

@Slava那么你会怎么做呢? –

回答

0

什么是语法,这样我就可以瓶坯:

messageCallback.subscribe(&B::callbk, b); 

你已经接口允许通过任何调用,和没有理由,使之更加复杂。 EventObject不应该知道回调是免费功能还是其他功能。我完全同意,std::bind是乏味和并不好看,我宁愿使用lambda:

EventObject<onMessageCallbackFunction> messageCallback; 
B b; 
messageCallback.subscribe([&b](const std::string& line){return b.callbk(line);}); 

PS:我不知道,如果我corretly了解你的动机使用tempalte。看来你只想用onMessageCallbackFunction s,这样简单地存储它们的向量应该没问题。

PPS:为完整起见这里是你怎么能隐藏方法中的bind

#include <vector> 
#include <string> 
#include <iostream> 
#include <functional> 
using std::placeholders::_1; 

template <class T> 
class EventObject { 
public: 
    void subscribe(const T& arg) 
    { 
     this->events.push_back(arg); 
    } 
    template<typename C> 
    void subscribe(void(C::*mem_fun)(const std::string&),C& c){ 
     subscribe(std::bind(mem_fun,c,_1)); 
    }  
    std::vector<T> events; 
}; 

typedef std::function<void(const std::string& line)> onMessageCallbackFunction; 

struct B { 
    void callbk(const std::string& line) {} 
}; 

int main(){ 
    EventObject<onMessageCallbackFunction> messageCallback; 
    B b; 
    messageCallback.subscribe(&B::callbk,b); 
} 

这仅仅是返回void,并返回一个string成员函数,但我wouldnt甚至懒得使其通用,只使用lambdas。

+0

不同的std :: function'事件类型可能需要回调具有不同参数的函数。 –

+0

是的,这工作,但它看起来像我将失去搜索向量的方法合格地址的能力。如果我希望“联合国” - 订阅一个对象。由于函数的地址是基于Lambda的。 –

+0

@StevenVenham我很好奇,试图得到你所要求的。它不看太糟糕了,但我真的难道不使用它,而是依靠lambda表达式 – user463035818

1

我的建议是使用lambda(std::bind是过时的就出来了,因为lambda表达式是在几乎每一个方式优越的一天)。

它从未伤害分别拼出拉姆达。这样做没有性能成本。编译器将取消不必要的副本。

我也使用std ::函数来存储您的信号,并从兼容的传递函数类型转换。

你调用点代码,那么看起来是这样的,我想你会同意是干净和表现:

EventObject<void(std::string)> messageCallback; 
B b; 

auto handler = [&b](std::string const& line) 
{ 
    b.callbk(line); 
}; 

messageCallback.subscribe(handler); 

完整的示例:

#include <string> 
#include <vector> 
#include <functional> 
#include <type_traits> 

template<class Sig> struct EventObject; 

template<class R, class...Args> 
struct EventObject<R (Args...)> 
{ 
    using slot_type = std::function<R(Args...)>; 

    template 
    < 
     class F, 
     typename std::enable_if 
     < 
      std::is_constructible 
      < 
       slot_type, 
       typename std::decay<F>::type 
      >::value 
     >::type * = nullptr 
    > 
    void subscribe(F&& f) 
    { 
     subscribers_.emplace_back(std::forward<F>(f)); 
    } 

    std::vector<slot_type> subscribers_; 
}; 

class B 
{ 
public: 
    void callbk(const std::string& line) {} 
}; 

int main() 
{ 
    EventObject<void(std::string)> messageCallback; 
    B b; 

    auto handler = [&b](std::string const& line) 
    { 
     b.callbk(line); 
    }; 

    messageCallback.subscribe(handler); 
} 
+0

提所以用这个例子,为什么会不一样的东西: 模板 \t无效SUB2(无效(j :: *本功能)(slot_type),J&研究所) \t { \t} 工作? –

+0

您需要将指针传递给J以及成员函数指针。然后它会非常具体。 –