2016-02-08 1 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 * в обратном вызове. Я просто привязываю функцию к этому, чтобы я мог использовать функцию-член как обратный вызов. – aardvarkk

ответ

2

Попробуйте

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

или попробовать функцию лямбда

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

Да, первый на самом деле работает! Я попытался связать только с заполнителями :: _ 1, но не вторым. Что это за вызов? – aardvarkk

+0

О, и ягненки в порядке - я уже использовал их, но вместо этого хотел переключиться на функцию-член. Это хороший вариант. – aardvarkk

+0

После некоторого чтения на bind(), я думаю, я это понимаю. Два заполнителя для параметров Touch * и Event *. По какой-то причине я подумал, что местозаполнитель определил положение передаваемого параметра I - «это». Вот почему я только включил его, когда попробовал. Но теперь я думаю, что вижу, что происходит! – aardvarkk

1

bind должно быть сказано, что делать с параметрами, передаваемыми в возвращаемого значения. По умолчанию он просто отбрасывает их.

Когда вы передаете его std::function, он пытается набрать его. std::function передает Touch*, Event* на номер bind. Возвращаемое значение bind отбрасывает их и вызывает (this->*&Game::onTouchEnded)(), как вы просили. Это недействительный вызов, и вы получаете сообщение об ошибке.

Простым способом исправить это является добавление заполнителей, которые говорят «что делать с аргументами для возвращаемого значения привязки». bind рассматривает функции-члены как функции, которые принимают дополнительный аргумент this. Вы хотите:

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

что соответствует:

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

Теперь это все хорошо, но на самом деле вы должны избегать std::bind. Полностью понять это сложно: у него есть странные угловые случаи, которые могут укусить вас или заставить вас бесполезно стирать шрифт, когда вы называете его рекурсивно.

Вместо этого используйте лямбда.В С ++ 11 он выглядит следующим образом:

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

В С ++ 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, но встроенный код стал довольно длинным и отвлекающим. Скажете ли вы, что использование однострочной лямбда, которая только пересылает параметры в функцию-член, превосходит вызов прямого вызова? Вот что я вроде собираю из вашего другого комментария выше. – aardvarkk

+1

@aardvarkk Да. Любой разработчик C++ должен понимать, по крайней мере, базовые lambdas, но немногие разработчики C++ полностью понимают 'bind'. И короткая лямбда, по крайней мере, такая же ясная, как «привязка». – Yakk