С++ 11 обратных вызовов?
У меня есть функция void внутри класса. В старом С++ я бы сделал функцию static, взяв имя класса в качестве параметра, и имел свой собственный класс, который принял статическую функцию void + void *, чтобы я мог легко ее называть.
Однако это кажется старой школой. Это также не шаблон, который чувствует, что я мог бы делать больше. Что является более современным способом создания обратных вызовов для myclassVar.voidReturnVoidParamFunc
Ответы
Ответ 1
Используйте std::function
и lambdas (или std::bind()
) для хранения вызовов:
#include <functional>
#include <iostream>
class Test
{
public:
void blah() { std::cout << "BLAH!" << std::endl; }
};
class Bim
{
public:
void operator()(){ std::cout << "BIM!" << std::endl; }
};
void boum() { std::cout << "BOUM!" << std::endl; }
int main()
{
// store the member function of an object:
Test test;
std::function< void() > callback = std::bind( &Test::blah, test );
callback();
// store a callable object (by copy)
callback = Bim{};
callback();
// store the address of a static function
callback = &boum;
callback();
// store a copy of a lambda (that is a callable object)
callback = [&]{ test.blah(); }; // often clearer -and not more expensive- than std::bind()
callback();
}
Результат:
BLAH!
BIM!
БУМ!
BLAH!
Скомпилирует и запустит: http://ideone.com/T6wVp
std::function
может использоваться как любой подлежащий перезаписи объект, поэтому не стесняйтесь хранить его где-то в качестве обратного вызова, например, в объекте. Это также означает, что вы можете свободно помещать его в стандартные контейнеры, например std::vector< std::function< void () > >
.
Также обратите внимание, что эквивалентные boost:: function и boost:: bind доступны в течение многих лет.
Ответ 2
Пример передачи параметров для обратного вызова С++ 11 с использованием Lambda и вектора см. в http://ideone.com/tcBCeO или ниже:
class Test
{
public:
Test (int testType) : m_testType(testType) {};
void blah() { std::cout << "BLAH! " << m_testType << std::endl; }
void blahWithParmeter(std::string p) { std::cout << "BLAH1! Parameter=" << p << std::endl; }
void blahWithParmeter2(std::string p) { std::cout << "BLAH2! Parameter=" << p << std::endl; }
private:
int m_testType;
};
class Bim
{
public:
void operator()(){ std::cout << "BIM!" << std::endl; }
};
void boum() { std::cout << "BOUM!" << std::endl; }
int main()
{
// store the member function of an object:
Test test(7);
//std::function< void() > callback = std::bind( &Test::blah, test );
std::function< void() > callback = std::bind( &Test::blah, test );
callback();
// store a callable object (by copy)
callback = Bim{};
callback();
// store the address of a static function
callback = &boum;
callback();
// store a copy of a lambda (that is a callable object)
callback = [&]{ test.blah(); }; // might be clearer than calling std::bind()
callback();
// example of callback with parameter using a vector
typedef std::function<void(std::string&)> TstringCallback;
std::vector <TstringCallback> callbackListStringParms;
callbackListStringParms.push_back( [&] (const std::string& tag) { test.blahWithParmeter(tag); });
callbackListStringParms.push_back( [&] (const std::string& tag) { test.blahWithParmeter2(tag); });
std::string parm1 = "parm1";
std::string parm2 = "parm2";
int i = 0;
for (auto cb : callbackListStringParms )
{
++i;
if (i == 1)
cb(parm1);
else
cb(parm2);
}
}