Qt invokeMethod and calling a static method? - c++

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();
}
};

Related

Passing a derived class into a map c++

What I would like to do is place a manager into a map, and then call functions correlating to each manager. Because I have different types of managers I created a base class like so:
class iGyroManager {
public:
iGyroManager() {}
virtual ~iGyroManager() = default;
virtual bool preInit() = 0;
virtual bool init() = 0;
virtual bool postInit() = 0;
virtual void update() = 0;
virtual void cleanup() = 0;
}
Pretty straight forward and obviously works like a charm.
Then I do the following to create a derived class:
class GyroAudioManager : public iGyroManager {
public:
GyroAudioManager();
~GyroAudioManager() override;
bool preInit() override;
bool init() override;
bool postInit override;
void update() override;
bool cleanup() override;
}
Again, simple and straight forward. The cpp is very basic and just declares the bare functions.
I then create one final derived class:
class GyroAppStateManager : iGyroManager {
private:
std::map<int, iGyroManager&> m_managerMap;
public:
GyroAppStateManager();
~GyroAppStateManager() override;
bool preInit() override;
bool init() override;
bool postInit() override;
int start();
void update() override;
bool registerManager(iGyroManager& manager);
bool cleanup() override;
}
That seems to work, but it's in the registerManager function where it falls apart:
bool GyroAppStateManager::registerManager(iGyroManager& manager) {
// Try to insert a derived class into a base class map using what
// should be working.
m_managerMap.insert(1, manager);
return true;
}
And in the calling function:
int start() {
GyroAudioManager m_audioManager = GyroAudioManager();
mp_appStateManager->registerManager(m_audioManager);
/* use mp_appStateManager here, while m_audioManager is alive */
}
Except this does not seem to work at all and spits out the following:
error: no matching function for call to std::map<int, iGyroManager&>::insert(int, iGyroManager&)
So my question is what am I doing wrong? As I mentioned above, I'd like to add multiple different manager classes that derive a single base class to this map and then be able to run certain functions from it.
Is there actually a way of doing it?
You can't have a standard container of references. I'm still looking for the exact wording of the restriction, but in the meantime you might want to try std::reference_wrapper instead, or a container of (smart) pointers, which also allows polymorphism.
Actually, value_type is std::pair<key_type, mapped_type> which is an object type even when mapped_type is a reference. So that's ok.
The error is caused because the parameter to std::map<Key,Value>::insert is a pair<Key,Value>, not two separate arguments. Try
m_managerMap.insert({1, manager});
But then you need to arrange to reference an object that isn't destroyed immediately afterward, when start() returns.

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...

Using Qt5 new connect syntax with inheritance

I am trying to use the new connect syntax in some legacy code but came upon an architectural problem. So let's pretend I have a BaseReader class that looks like this :
class BaseReader : public QObject
{
Q_OBJECT
public:
BaseReader();
public slots:
virtual void read(const fstream& myStream);
}
Then let's say I have some children classes like this
class Reader1 : public BaseReader
{
Q_OBJECT
public:
BaseReader();
public slots:
virtual void read(const fstream& myStream);
}
Some of the read work is done in the base class, some in the child class. I have about 4 classes that are switched around at runtime. I have a connectReaders function that looks like this :
void connectReaders(BaseReader* currentReader)
{
connect(this, SIGNAL(mustRead(const fstream&)), currentReader, SLOT(read(const fstream&)));
}
Now it is my understanding that if I use the new syntax I will connect to the base member function no the overloaded versions. Is that correct ? Is there any way to connect these signals using the new syntax without modifying the architecture ? My example is very simplified and modifying that code would require a couple of months (including tests). It works the old way but I would like to take advantage of the new syntax. Any ideas ?
I have looked at these threads but they do not seem to offer a solution to this problem :
This is the other way around:
Using Qt signals and slots with multiple inheritance
I have read this but I am not sure I understand how the overload
section applies: https://wiki.qt.io/New_Signal_Slot_Syntax
I have qt5.4.1, Visual Studio 2013.
There's no problem when using the new 'connect' syntax with virtual slots and base class object pointers. You're specifying the object instance (e. g. currentReader), and the specific method to be called will be resolved using this object's virtual methods table.
Disclaimer: I am not familiar with Qt. The question here however, seems to be a C++ question.
When using a pointer-to-member to a virtual function in a base class, on a pointer/reference to a derived class, an override in the derived class will be called (if it exists).
class Base
{
public:
virtual void f()
{
std::cout << "Base\n";
}
};
class Derived : public Base
{
public:
virtual void f()
{
std::cout << "Derived\n";
}
};
int main()
{
void (Base::* pmf)() = &Base::f;
Derived d;
(d.*pmf)();
}
Will print "Derived", not "Base";
If a Qt signal calls your member function pointer with a derived object, the function override will therefore get called.

QtConcurrent number of arguments error

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);

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);
//^^^^^^^^^
};