QtConcurrent number of arguments error - c++

I have a QMainWindow class.
class MainWindow: public QMainWindow
{
Q_OBJECT
...
public:
void insertVector();
...
};
and I have class SqlStorage to make operation with Data Base.
class SqlStorage : public QObject {
Q_OBJECT
...
public:
static void loadSQL();
...
};
In insertVector() method I try to asynchronously write in DB.
void MainWindow::insertVector()
{
SqlStorage* _sqlStorage = new SqlStorage;
QFuture<void> future = QtConcurrent::run(_sqlStorage, &SqlStorage::loadSQL);
}
But when I try to compile, I have error that: "term does not evaluate to a function taking 1 arguments".
Where is my problem?

When you want to call static member functions with QtConcurrent::run, you do it the same way you call a regular non-member function. Only difference is you include the class scope in it. Like this:
QFuture<void> future = QtConcurrent::run(SqlStorage::loadSQL);

Related

Qt invokeMethod and calling a static method?

Is it possible to call a static method?
I am using:
QMetaObject::invokeMethod(this
,strThread.toLatin1()
,Qt::DirectionConnection
,Q_ARG(clsThread*, this));
This works, however I want to call a static method and that doesn't work, is it possible to invoke a static method?
I've tried assigning to strThread: "clsScriptHelper::threadFun", but this doesn't work.
I couldn't get the static method to work, so I've implemented an alternative solution. In my derived thread class I added a member which has the type:
QObject* mpobjClass;
I then added a method to set this:
void setClassPtr(QObject* pobjClass) { mpobjClass = pobjClass; }
My invoke now looks like this:
QMetaObject::invokeMethod(mpobjClass
,strThread.toLatin1()
,Qt::DirectConnection
,Q_ARG(clsThread*, this));
This works for me.
yes, you can, but the method must be annotates as invocable i.e Q_INVOKABLE see what qt documented about it...
Foo obj;
QMetaObject::invokeMethod(&obj, "amSomething", Qt::DirectConnection);
and Foo should look like:
class Foo : public QObject
{
Q_OBJECT
public:
explicit Foo(QObject *parent = nullptr);
Q_INVOKABLE static void amSomething(){ qDebug() << "am in static";}
signals:
public slots:
};
Why would you do that? invokeMethod is for when the object has a dynamic type and you got an instance and want to call a method on that instance in spite of not knowing anything about the type.
What you seem to want to do is to dispatch static methods based on a string name. That's not hard and doesn't require invokeMethod:
class Class {
public:
static void method1();
static void method2();
static void dispatchByName(const char *name) {
if (QByteArrayLiteral("method1") == name) method1();
else if (QByteArrayLiteral("method2") == name) method2();
}
};

How to pass a member function to a class constructor?

I want to pass my class Worker a pointer to a funtion, but something is wrong when im calling the constructor...
Worker.h
class Worker : public QObject
{
Q_OBJECT
public:
Worker(void (*process)());
public slots:
void work();
signals:
void error(QString error);
void paused();
private:
void (*_task)();
};
Worker.cpp:
Worker::Worker(void (*task)())
{
_task = task;
}
void Worker::work()
{
_task();
paused();
}
This is what i want to do...
Worker should perform a function call of any function.
(Update is a void without attributes, not static or const etc.)
Main.cpp:
_worker = new Worker(someClass->Update());
First, when a function is a non static member function of a class, its first argument is the object from which its called.
In your example, the real code for your function Update() from the object someClass is "void Update(&someClass)"
Secondly, when you do Update(), you call the function and so, takes its return in your Worker constructor.
To use member function pointers, the syntax is : &ClassType::FunctionName
To use 'normal' function pointers, the syntax is : &FunctionName
In your exemple, you can for exemple turn Update function to static and change your constructor like this :
_worker = new Worker(&someClassType::Update);
Like someone said in the comments, if you want to improve your code, learn about std::function from C++11
Just a variant of FĂ©licie's answer.
If you want to be able to pass methods operating on arbitrary objects, the C++11 way will be to use std::function and std::bind.
If for any reason you must use a pre C++11 system, you will have to revert to the C-ish style of passing arbitrary arguments, the good old void * type:
void someClassUpdateWrapper(void *obj) {
SomeClassType someClass = static_cast<SomeClassType *>(obj);
someClass->Update();
}
You will have to slightly change your declarations:
class Worker : public QObject
{
Q_OBJECT
public:
Worker(void (*process)(), void *obj);
...
private:
void (*_task)();
void *_obj;
};
then:
Worker::Worker(void (*task)(), void *obj;)
{
_task = task;
_obj = obj;
}
void Worker::work()
{
_task(_obj);
paused();
}
and finaly:
_worker = new Worker(someClassUpdateWrapper, static_cast<void *>(someClass));
But this looses all the possible type controls allowed by the C++11 way - the reason why std::function and std::bind were invented...

Virtual method misconception in C++

I am not experienced in OOP. I am developing an application using C++ and Qt. I have implemented 2 classes, base one and the one that inherits from it. Then I have added virtual methods for both and everything worked. But then I realized that I don't think it should... Here is the example:
This is my base class :
namespace Ui {
class CGenericProject;
}
class CGenericProject : public QDialog
{
Q_OBJECT
public:
explicit CGenericProject(QWidget *parent = 0);
~CGenericProject();
EMeasures_t type();
private:
Ui::CGenericProject *ui;
virtual void initPlot();
protected:
QCustomPlot* customPlot;
QVector<double> m_x;
QVector<double> m_y;
EMeasures_t m_type;
};
It has a virtual method called initPlot and it looks like this:
void CGenericProject::initPlot()
{
customPlot = ui->workPlot;
customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectAxes );
customPlot->setFocusPolicy(Qt::ClickFocus);
customPlot->xAxis->setAutoTickStep(false);
customPlot->yAxis->setAutoTickStep(false);
customPlot->xAxis->setTickStep(100);
customPlot->yAxis->setTickStep(100);
customPlot->xAxis->setRange(0, 1000);
customPlot->yAxis->setRange(0, 1000);
}
And then i have a class that derives it:
class CEisProject : public CGenericProject
{
public:
CEisProject();
~CEisProject();
private:
virtual void initPlot();
void exampleEisMethod();
};
its initPlot is here:
void CEisProject::initPlot()
{
// give the axes some labels:
customPlot->xAxis->setLabel("Re [Ohm]");
customPlot->yAxis->setLabel("- Im [Ohm]");
customPlot->replot();
}
This is how i create the object:
CGenericProject* test = new CEisProject();
Now, when the initPlot() method is called, first the initPlot() from base class CGenericProject is called and then initPlot() from CEisProject is called. I wanted this functionality, where I can predefine some stuff in generic class and then add specific stuff in the childs.
But when I think of it, shouldn't initPlot() be calles exclusevily? I mean, shouldn't the method be called from base class or child class, instead of both, one after another? I have noticed this after reading this answer.
Constructors:
CGenericProject::CGenericProject(QWidget *parent) :
QDialog(parent),
ui(new Ui::CGenericProject)
{
ui->setupUi(this);
initPlot();
m_x.clear();
m_y.clear();
}
CEisProject::CEisProject()
{
m_type = EMeasures_t::eEIS;
initPlot();
}
You did not show the definition of the constructors, just their declaration. But I'm pretty sure the constructor definitions contain the answer to your question.
You may not be aware that the derived class constructor calls the base class constructor before directing virtual functions to the derived class. So a virtual function called in the base class construction (of an object which will soon be derived class) gets the base class definition of that virtual function.
Also, your constructor should be like:
// File .h
CEisProject(QWidget *parent = 0);
// File .cpp
CEisProject::CEisProject(QWidget *parent) : CGenericProject(parent)
{
...
}
or you won't be able to parent your derived widgets.

QMetaObject::invokeMethod: No such method when using inheritance

I have got a super class Common, which inherits from QObject. Then I have got a class Item, which inherits from Common.
Common.h
class Common : public QObject {
Q_OBJECT
public:
// some methods
};
Item.h
class Item : public Common {
Q_OBJECT
public:
// some methods
void test(QString value);
};
Item.cpp
void Item::test(QString value) {
qDebug() << value;
}
I want to use QMetaObject::invokeMethod to dynamically call a function.
So I implemented a test function in the Item class, which takes exactly one string.
Item* item = new Item();
QMetaObject::invokeMethod(item, "test", Qt::DirectConnection, Q_ARG(QString, "1234"));
This does not work. I get the following error: QMetaObject::invokeMethod: No such method Common::test(QString), which is perfectly okay and fine, because the Common class has no test function.
How can I tell QMetaObject::invokeMethod, that it should call the method from the Item class?
QMetaObject::invokeMethod can only invoke methods known to the Qt meta object system. These are slots and "invokable" functions, the latter being functions with the keyword Q_INVOKABLE before them.
So either write:
class Item : public Common {
Q_OBJECT
public slots:
// ^^^^^
void test(QString value);
};
or:
class Item : public Common {
Q_OBJECT
public:
Q_INVOKABLE void test(QString value);
//^^^^^^^^^
};

QT : Templated Q_OBJECT class

Is it possible to have a template class, which inherit from QObject (and has Q_OBJECT macro in it's declaration)?
I would like to create something like adapter for slots, which would do something, but the slot can take arbitrary number of arguments (number of arguments depends on the template argument).
I just tried doing it, and got linker errors. I guess gmake or moc is not getting called on this template class. Is there a way to do this? Maybe by explicitly instantiating templates?
It is not possible to mix template and Q_OBJECT but if you have a subset of types you can list the slots and signals like this:
class SignalsSlots : public QObject
{
Q_OBJECT
public:
explicit SignalsSlots(QObject *parent = 0) :
QObject(parent) {}
public slots:
virtual void writeAsync(int value) {}
virtual void writeAsync(float value) {}
virtual void writeAsync(double value) {}
virtual void writeAsync(bool state) {}
virtual void writeAsync(svga::SSlideSwitch::SwitchState state) {}
signals:
void readAsynkPolledChanged(int value);
void readAsynkPolledChanged(float value);
void readAsynkPolledChanged(double value);
void readAsynkPolledChanged(bool state);
void readAsynkPolledChanged(svga::SSlideSwitch::SwitchState state);
};
...
template <class T>
class Abstraction : public SignalsSlots
{...
Taking into account some restrictions: you can.
First please became familiar (if already not) https://doc.qt.io/archives/qq/qq16-dynamicqobject.html. - it will help to imlement it.
And about restrictions: you can have a template QObject class i.e. template class derived from QObject, but:
Do not tell the moc to compile it.
Q_OBJECT is just a macro and you have to replace it by it real
content which is virtual interface and something else :)
Implement QMetaObject activation (above mentioned virtual interface
and be caution with object info data, which is also come from
Q_OBJECT) and some else functionality and you will have template
QObject (even with template slots)
But as I managed to catch the one draw back - it is not possible to
simply use this class as a base for another class.
There are some other drawbacks - but I think the detail
investigation will show you them.
Hope this will helpful.
It is still not possible to mix templates and Q_OBJECT but depending on your use case you may use the new 'connect'-syntax. This allows at least the usage of template-slots.
Classical non-working approach:
class MySignalClass : public QObject {
Q_OBJECT
public:
signals:
void signal_valueChanged(int newValue);
};
template<class T>
class MySlotClass : public QObject {
Q_OBJECT
public slots:
void slot_setValue(const T& newValue){ /* Do sth. */}
};
Desired usage but not compilable:
MySignalClass a;
MySlotClass<int> b;
QObject::connect(&a, SIGNAL(signal_valueChanged(int)),
&b, SLOT(slot_setValue(int)));
Error: Template classes not supported by Q_OBJECT (For
MySlotClass).
Solution using new the 'connect'-syntax:
// Nothing changed here
class MySignalClass : public QObject {
Q_OBJECT
public:
signals:
void signal_valueChanged(int newValue);
};
// Removed Q_OBJECT and slots-keyword
template<class T>
class MySlotClass : public QObject { // Inheritance is still required
public:
void slot_setValue(const T& newValue){ /* Do sth. */}
};
Now we can instantiate desired 'MySlotClass'-objects and connect them to appropriate signal emitters.
MySignalClass a;
MySlotClass<int> b;
connect(&a, &MySignalClass::signal_valueChanged,
&b, &MySlotClass<int>::slot_setValue);
Conclusion: Using template-slots is possible. Emitting template signals is not working since a compiler error will occur due to missing Q_OBJECT.
I tried explicitly instantiating templates, and got this :
core_qta_qt_publisheradapter.hpp:96: Error: Template classes not supported by Q_OBJECT
I guess that answers my question.
EDIT
Actually, if I place whole template class definition in the header, then the qt preprocessor doesn't process it, and then I get linker errors. Therefore it must be possible to do it, if I add missing methods.
EDIT #2
This library did exactly what I wanted - to use a custom signal/slot mechanism, where the slot has not-defined signature.