2016-02-08 74 views
1

我試圖掛鉤一個成員函數,最大回調爲std::function。回調的類型是:沒有可行的重載'='用於將std :: function回調分配爲成員函數

std::function<void(Touch*, Event*)> 

我的成員函數是:

void Game::onTouchEnded(Touch* touch, Event* event) 

當我嘗試使用分配回調如下:

listener->onTouchEnded = bind(&Game::onTouchEnded, this); 

我得到一個No viable overloaded '='錯誤有幾個候選人。這裏有一個我認爲是最相關的細節:

Candidate function not viable: no known conversion from 
'__bind<void (Game::*)(cocos2d::Touch *, cocos2d::Event *), Game *>' 
to 
'std::__1::function<void (cocos2d::Touch *, cocos2d::Event *)>' 
for 1st argument` 

我試過幾個不同的bind()的安排,但我不知道是什麼錯誤是告訴我。這些類型在參數和返回值方面似乎都是正確的,所以我不確定它爲什麼不接受它?

+0

嘗試添加兩個'std :: placeholders'。 – LogicStuff

+0

你需要通過第二個參數 – sunny1304

+0

@LogicStuff @ sunny1304雖然我沒有別的東西可以綁定。這些參數將在回調中傳遞給* me *。我只是將函數綁定到'this',以便我可以使用成員函數作爲回調函數。 – aardvarkk

回答

2

嘗試

listener->onTouchEnded = bind(&Game::onTouchEnded, this, std::placeholders::_1, std::placeholders::_2); 

,或者嘗試一個lambda函數

listener->onTouchEnded = [this](Touch* touch, Event* event){ this->onTouchEnded(touch, event); }; 
+0

呵呵,第一個實際工作!我曾嘗試綁定僅佔位符:: _ 1,但不是第二個。這個綁定調用實際上在做什麼? – aardvarkk

+0

哦,lambdas很好 - 我已經在使用它們,但是想切換到成員函數。不過,這是一個不錯的選擇。 – aardvarkk

+0

經過對bind()的更多閱讀之後,我想我明白了。這兩個佔位符用於Touch *和Event *參數。出於某種原因,我認爲佔位符定義了我傳遞參數的位置 - 「this」。這就是爲什麼當我嘗試時只包括一個。但現在我想我明白髮生了什麼事情! – aardvarkk

1

bind必須被告知如何處理傳遞給它的返回值參數做。默認情況下,它只是丟棄它們。

當您將它傳遞給std::function時,它會嘗試鍵入它。 std::functionTouch*, Event*傳遞給bindbind的返回值丟棄它們,並按要求調用(this->*&Game::onTouchEnded)()。這不是一個有效的電話,而且你會得到一個錯誤。

解決此問題的簡單方法是添加佔位符,指出「對綁定返回值的參數做什麼」。 bind將成員函數視爲首先採用額外this參數的函數。你想:

(this->*&Game::onTouchEnded)(_1, _2) 

對應於:

std::bind(&Game::onTouchEnded, this, _1, _2) 

現在,這一切都很好,但真的是你應該避免std::bind。充分理解它是棘手的:當你遞歸地調用它時,它有可能咬你的奇怪的角落案例,或者迫使你不必要地進行類型擦除。

而是使用lambda。在C++ 11,它看起來像:

[this](Touch* touch, Event* event){return this->onTouchEnded(touch, event);} 

在C++ 14,替代的是:

[this](auto&&args)->decltype(auto){return this->onTouchEnded(decltype(args)(args)...);} 

甚至:

template<class T, class M> 
auto bind_method(T* t, M* m) { 
    return [t, m](auto&&...args)->decltype(auto){ 
    return (t->*m)(decltype(args)(args)...); 
    }; 
} 

其可以像這樣使用:

bind_method(this, &Game::onTouchEnded) 

,是一個簡易替換您的來電bind。在這裏,我們將參數自動轉發給我們所調用的方法,而不是必須顯式列出它們。

+0

我實際上是在使用lambdas,但內聯代碼開始變得非常冗長和分散注意力。你會說使用只將參數轉發給成員函數的單行lambda優於直接調用bind嗎?這是我從上面的其他評論收集的。 – aardvarkk

+1

@aardvarkk是的。任何C++開發人員都應該理解至少基本的lambda表達式,但很少有C++開發人員完全理解「bind」。一個簡短的lambda至少和'bind'一樣清晰。 – Yakk

相關問題