2017-09-26 36 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以及成員函數指針。然後它會非常具體。 –