英文:
How to store an instance of QPropertyChangeHandler?
问题
QProperty::onValueChange()
返回一个 QPropertyChangeHandler 对象,我认为应该将它存储为成员变量,以便它不会被销毁,从而取消注册 Functor。
由于 QPropertyChangeHandler
是一个接受 Functor 的模板类,我需要提供我要使用的 Functor 类型,但我不确定应该放什么类型。
如何存储返回的 QPropertyChangeHandler
对象?
以下是到目前为止我最好的尝试:
Proptest.h
#ifndef PROP_TEST
#define PROP_TEST
#include <QObject>
#include <QProperty>
#include <QString>
#include <QPropertyChangeHandler>
#include <functional>
class PropTest : public QObject {
Q_OBJECT
public:
QProperty<QString> m_property;
PropTest();
~PropTest() = default;
QPropertyChangeHandler<std::function<void()>> propertyChangeHandler;
void TestFunction();
};
#endif
Proptest.cpp
#include <QObject>
#include <QString>
#include <QDebug>
#include <QApplication>
#include "prop_test.h"
PropTest::PropTest() { // <- error occurs here
this->propertyChangeHandler = this->m_property.onValueChanged(&PropTest::TestFunction);
}
void PropTest::TestFunction() {
// further processing
}
int main(int argc, char* argv[]) {
auto app = QApplication(argc, argv);
auto obj = new PropTest{};
obj->m_property = "String";
obj->m_property = "New";
app.exec();
}
但是我得到了这个陌生的错误:
[build] prop_test.cpp: In constructor 'PropTest::PropTest()':
[build] prop_test.cpp:11:20: error: no matching function for call to 'QPropertyChangeHandler<std::function<void()> >::QPropertyChangeHandler()'
[build] 11 | PropTest::PropTest() {
[build] | ^
我觉得错误出现的地方很奇怪。
英文:
QProperty::onValueChange()
returns a QPropertyChangeHandler object which I believe should be stored as a member variable so it will not be destroyed and consequently de-registering the Functor.
Since QPropertyChangeHandler
is a Template class that takes a Functor, I need to provide the type of Functor that I am going to use but I am not sure what type to place there.
How should I store the returned QPropertyChangeHandler
object?
The following are my best attempt so far:
Proptest.h
#ifndef PROP_TEST
#define PROP_TEST
#include <QObject>
#include <QProperty>
#include <QString>
#include <QPropertyChangeHandler>
#include <functional>
class PropTest : public QObject {
Q_OBJECT
public:
QProperty<QString> m_property;
PropTest();
~PropTest() = default;
// QString m_property;
QPropertyChangeHandler< std::function<void()> > propertyChangeHandler;
void TestFunction();
};
#endif
Proptest.cpp
#include <QObject>
#include <QString>
#include <QDebug>
#include <QApplication>
#include "prop_test.h"
PropTest::PropTest() { // <- error occurs here
this->propertyChangeHandler = this->m_property.onValueChanged(&PropTest::TestFunction);
}
void PropTest::TestFunction() {
// further processing
}
int main(int arc, char* argv[]) {
auto app = QApplication(arc, argv);
auto ob = new PropTest{};
ob->m_property = "String";
ob->m_property = "New";
app.exec();
}
But all I got was this unfamiliar error:
[build] prop_test.cpp: In constructor 'PropTest::PropTest()':
[build] prop_test.cpp:11:20: error: no matching function for call to 'QPropertyChangeHandler<std::function<void()> >::QPropertyChangeHandler()'
[build] 11 | PropTest::PropTest() {
[build] | ^
and I find the place where the error occurs bizarre.
答案1
得分: 1
让我们按顺序进行。<br/>免责声明:不幸的是,我犯了一个错误,下载了 Visual Studio 的非英语版本,从未改回来,因此我没有精确的错误消息。
你应该注意到的第一个错误是在 QPropertyChangeHandler<[...]>
的代码行中没有默认构造函数。
通过将
this->propertyChangeHandler = this->m_property.onValueChanged(&PropTest::TestFunction);
从构造函数的主体中移出,并放到类的初始化列表中,可以轻松修复这个问题。
解决了这个错误后,现在是时候解决类型混乱的问题了。
PropTest::TestFunction
方法的确切类型是 void(PropTest::*)()
;这与 void()
是不同的类型,因为对于类的方法来说,指针 this
总是作为参数传递的。
因为将 this
视为参数,所以你不能这样做:
propertyChangeHandler(m_property.onValueChanged(&PropTest::TestFunction))
如果尝试这样做,你会得到来自 Qt 的错误消息(来自 QProperty.h
中的静态断言):Functor callback must be callable without any parameters
。
假设你想在处理程序中连接的函数需要是对象方法(而不是单独的函数或静态方法),有几种解决方法:
- 第一个解决方案使用一个函数对象,其中包含你的对象作为其成员。<br/>头文件:
class PropTest;
struct TestFunctor {
public:
TestFunctor(PropTest* propTestObject);
void operator () () const;
private:
PropTest* object;
};
和源文件:
TestFunctor::TestFunctor(PropTest* propTestObject)
: object(propTestObject)
{
}
void TestFunctor::operator()() const {
object->TestFunction();
}
有了这个解决方案(只有这个解决方案),propertyChangeHandler
的类型必须更改为 QPropertyChangeHandler<TestFunctor>
,并使用以下方式构造:propertyChangeHandler( m_property.onValueChanged(TestFunctor(this)))
。
- 第二个解决方案是使用 lambda 表达式。例如:
PropTest::PropTest()
: QObject(),
propertyChangeHandler(m_property.onValueChanged(std::function<void()>([=]() { this->TestFunction(); })))
{
}
如果你决定采用这种方式(与你的问题相同),propertyChangeHandler
的类型是 QPropertyChangeHandler< std::function<void()> >
。
- 第三个解决方案是使用 bind 来绑定
TestFunction
方法。
PropTest::PropTest()
: QObject(),
propertyChangeHandler(m_property.onValueChanged(std::function<void()>(std::bind(&PropTest::TestFunction, this)))
{
}
- 如果你可以将类方法
TestFunction()
转化为单独的函数或静态方法,问题就会变得简单很多。propertyChangeHandler
的类型分别需要是QPropertyChangeHandler<void()>
(用于单独函数)或QPropertyChangeHandler<void(*)()>
(用于静态方法)。
最后,代码可以编译通过!!
附注:如果函数不需要连接到对象实例,我会选择解决方案 4。否则,我会选择解决方案 2 或解决方案 3。
英文:
Let us proceed in order.<br/>Disclaimer: unfortunately, I made the mistake of downloading a non-English version of Visual studio and never changed it back so I do not have the exact error messages.
The first error you sould have notice is in the lines of QPropertyChangeHandler<[...]>
has no default constructor.
This is easily corrected by moving
this->propertyChangeHandler = this->m_property.onValueChanged(&PropTest::TestFunction);
out of the constructor's body and into the initialization list of your class.
With that error out of the way, it is time to solve the type mess.
The exact type of the PropTest::TestFunction
method is void(PropTest::*)()
; this is a different type from void()
because inherently, for class' methods, the pointer this
is always going to be an argument.
Because this
is considered an argument, you cannot do:
propertyChangeHandler(m_property.onValueChanged(&PropTest::TestFunction))
If you try, you get the error message from Qt (from a static assert in QProperty.h
): Functor callback must be callable without any parameters
.
Assuming the function you want to connect in the handler needs to be an object method (not a separate function, not a static method), there are several ways to solve this:
-
First solution uses a functor, with your object as its member.<br/>Header:
class PropTest; struct TestFunctor { public: TestFunctor(PropTest* propTestObject); void operator () () const; private: PropTest* object; };
And source:
TestFunctor::TestFunctor(PropTest* propTestObject) : object(propTestObject) { } void TestFunctor::operator()() const { object->TestFunction(); }
With that solution (and that solution only), the type of
propertyChangeHandler
must be changed toQPropertyChangeHandler<TestFunctor>
and it is constructed with<br/>propertyChangeHandler( m_property.onValueChanged(TestFunctor(this)))
. -
Second solution is to use a lambda. For instance:
PropTest::PropTest() : QObject(), propertyChangeHandler(m_property.onValueChanged(std::function<void()>([=]() { this->TestFunction(); }))) { }
The type of
propertyChangeHandler
isQPropertyChangeHandler< std::function<void()> >
if you decide to proceed this way (i.e. same as your question). -
Third solution is to bind the
TestFunction
method.PropTest::PropTest() : QObject(), propertyChangeHandler(m_property.onValueChanged(std::function<void()>(std::bind(&PropTest::TestFunction, this)))) { }
-
If you can turn the class method
TestFunction()
into a separate function or into a static method, it simplifies the issue quite a bit. The type of propertyChangeHandler needs to be, respectivelyQPropertyChangeHandler<void()>
(for a separate function) orQPropertyChangeHandler<void(*)()>
(for a static method).
And finally, it compiles!!
PS: If the function does not need to be attached to an object instance, I would use solution 4. Otherwise, I would go for either solution 2 or solution 3.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论