C++ 绑定回调到 class
C++ binding callbacks to a class
我正在 class 中注册到散列映射的回调以处理各种 'events',所以我使用 std::function
将它们存储在散列映射中
我希望将回调绑定到 class 以便它们可以访问一些常用方法,因此我使用 std::bind
来完成此操作。
我不明白的是为什么第一个示例有效,但是当我尝试重构对 bindEvent
函数的 std::bind
调用时,编译失败。
所以这有效:
void MyClass::bindEvent(const QString event, std::function<QJsonObject(const QString &, const QJsonObject &)> handler)
{
mHandlers.insert(event.toLower(), handler);
}
void MyClass::registerAll()
{
this->bindEvent(QStringLiteral("do_something"), std::bind(&MyClass::doSomething, this, _1, _2));
this->bindEvent(QStringLiteral("do_something_else"), std::bind(&MyClass::doSomethingElse, this, _1, _2));
}
这失败了:
void MyClass::bindEvent(const QString event, std::function<QJsonObject(const QString &, const QJsonObject &)> handler)
{
mHandlers.insert(event.toLower(), std::bind(handler, this, _1, _2));
}
void MyClass::registerAll()
{
this->bindEvent(QStringLiteral("do_something"), &MyClass::doSomething);
this->bindEvent(QStringLiteral("do_something_else"), &MyClass::doSomethingElse);
}
错误信息:
../src/MyClass.cpp: In member function ‘virtual bool MyClass::registerAll()’:
../src/MyClass.cpp:124:388: error: no matching function for call to ‘MyClass::bindEvent(QString, QJsonObject (MyClass::*)(const QString&, const QJsonObject&))’
this->bindEvent(QStringLiteral("do_something"), &MyClass::doSomething);
^
../src/MyClass.cpp:124:388: note: candidate is:
../src/MyClass.cpp:109:6: note: void MyClass::bindEvent(QString, std::function<QJsonObject(const QString&, const QJsonObject&)>)
void MyClass::bindEvent(const QString event, std::function<QJsonObject(const QString &, const QJsonObject &)> handler)
^
../src/MyClass.cpp:109:6: note: no known conversion for argument 2 from ‘QJsonObject (MyClass::*)(const QString&, const QJsonObject&)’ to ‘std::function<QJsonObject(const QString&, const QJsonObject&)>’
散列本身声明为
QHash<const QString, std::function<QJsonObject(const QString &, const QJsonObject &)> > mHandlers;
我认为问题可能在于它不是一个函数,而是一个包含在 class 或命名空间中的函数。我认为你需要在签名中指定它。
或者使用 lambda 表达式可能会导致解决方法。由于您没有提供最小的工作示例,因此我无能为力。创建时,您可能会发现问题所在或让人们发现您的错误。
第二次尝试失败,因为需要在对象上调用成员函数。当您传递 pointer-to-member-function 时,没有对象可以调用该函数,因此无法将其转换为 std::function
.
你可以坚持现在做的事情,也可以在bindEvent
中接受一个pointer-to-member-function。
void MyClass::bindEvent(const QString event, QJsonObject (MyClass::*handler)(const QString &, const QJsonObject &))
{
mHandlers.insert(event.toLower(), std::bind(handler, this, _1, _2));
}
这里要指出的另一件事是,不久前就建议使用 lambda 而不是 std::bind
。据我了解,它为编译器提供了更好的机会来优化代码。
我个人也觉得它更具可读性。
void MyClass::bindEvent(const QString event, QJsonObject (MyClass::*handler)(const QString &, const QJsonObject &))
{
mHandlers.insert(event.toLower(), [&, handler](const QString& s, const QJsonObject& o){
this->*handler(s, o);
});
}
我正在 class 中注册到散列映射的回调以处理各种 'events',所以我使用 std::function
将它们存储在散列映射中
我希望将回调绑定到 class 以便它们可以访问一些常用方法,因此我使用 std::bind
来完成此操作。
我不明白的是为什么第一个示例有效,但是当我尝试重构对 bindEvent
函数的 std::bind
调用时,编译失败。
所以这有效:
void MyClass::bindEvent(const QString event, std::function<QJsonObject(const QString &, const QJsonObject &)> handler)
{
mHandlers.insert(event.toLower(), handler);
}
void MyClass::registerAll()
{
this->bindEvent(QStringLiteral("do_something"), std::bind(&MyClass::doSomething, this, _1, _2));
this->bindEvent(QStringLiteral("do_something_else"), std::bind(&MyClass::doSomethingElse, this, _1, _2));
}
这失败了:
void MyClass::bindEvent(const QString event, std::function<QJsonObject(const QString &, const QJsonObject &)> handler)
{
mHandlers.insert(event.toLower(), std::bind(handler, this, _1, _2));
}
void MyClass::registerAll()
{
this->bindEvent(QStringLiteral("do_something"), &MyClass::doSomething);
this->bindEvent(QStringLiteral("do_something_else"), &MyClass::doSomethingElse);
}
错误信息:
../src/MyClass.cpp: In member function ‘virtual bool MyClass::registerAll()’:
../src/MyClass.cpp:124:388: error: no matching function for call to ‘MyClass::bindEvent(QString, QJsonObject (MyClass::*)(const QString&, const QJsonObject&))’
this->bindEvent(QStringLiteral("do_something"), &MyClass::doSomething);
^
../src/MyClass.cpp:124:388: note: candidate is:
../src/MyClass.cpp:109:6: note: void MyClass::bindEvent(QString, std::function<QJsonObject(const QString&, const QJsonObject&)>)
void MyClass::bindEvent(const QString event, std::function<QJsonObject(const QString &, const QJsonObject &)> handler)
^
../src/MyClass.cpp:109:6: note: no known conversion for argument 2 from ‘QJsonObject (MyClass::*)(const QString&, const QJsonObject&)’ to ‘std::function<QJsonObject(const QString&, const QJsonObject&)>’
散列本身声明为
QHash<const QString, std::function<QJsonObject(const QString &, const QJsonObject &)> > mHandlers;
我认为问题可能在于它不是一个函数,而是一个包含在 class 或命名空间中的函数。我认为你需要在签名中指定它。
或者使用 lambda 表达式可能会导致解决方法。由于您没有提供最小的工作示例,因此我无能为力。创建时,您可能会发现问题所在或让人们发现您的错误。
第二次尝试失败,因为需要在对象上调用成员函数。当您传递 pointer-to-member-function 时,没有对象可以调用该函数,因此无法将其转换为 std::function
.
你可以坚持现在做的事情,也可以在bindEvent
中接受一个pointer-to-member-function。
void MyClass::bindEvent(const QString event, QJsonObject (MyClass::*handler)(const QString &, const QJsonObject &))
{
mHandlers.insert(event.toLower(), std::bind(handler, this, _1, _2));
}
这里要指出的另一件事是,不久前就建议使用 lambda 而不是 std::bind
。据我了解,它为编译器提供了更好的机会来优化代码。
我个人也觉得它更具可读性。
void MyClass::bindEvent(const QString event, QJsonObject (MyClass::*handler)(const QString &, const QJsonObject &))
{
mHandlers.insert(event.toLower(), [&, handler](const QString& s, const QJsonObject& o){
this->*handler(s, o);
});
}