Getting around Qt's templating restrictions - c++

I want to write a simple flexible ftp server in C++ that can be parametrized with a class to handle the user (check login and password, deliver files etc.) supplied on server initialization.
So I came up with this neat (so I thought) idea:
class FtpDelegate
{
public:
FtpDelegate() {}
virtual ~FtpDelegate() {}
virtual bool login(QString username, QString password) = 0;
// ...
};
class DummyDelegate : public FtpDelegate
{
public:
virtual bool login(QString username, QString password)
{
return true;
}
};
template<class Delegate>
class FtpServer : public QObject, Derived_from<Delegate, FtpDelegate>
{
Q_OBJECT
public:
explicit FtpServer(const QHostAddress &address = QHostAddress::Any,
quint16 port = 21,
QObject *parent = 0);
public slots:
void newConnection();
private:
QTcpServer *server;
QHostAddress address;
};
template <class Delegate>
void FtpServer<Delegate>::newConnection()
{
FtpDelegate *delegate = new Delegate();
new FtpConnection (delegate, server->nextPendingConnection(), address, this);
}
class FtpConnection : public QObject
{
Q_OBJECT
public:
explicit FtpConnection(FtpDelegate *delegate,
QTcpSocket *socket,
const QHostAddress &address,
QObject *parent = 0);
public slots:
void newDataConnection();
private:
QTcpSocket *socket;
QTcpServer *dataServer; // needed to transfer data to user
QTcpSocket *dataSocket;
};
// server initialization
FtpServer<DummyDelegate> ftpServer();
and then (you probably saw that coming) bam!
Error: Template classes not supported by Q_OBJECT
it is likely that there are other errors or misconceptions too as I am only starting to learn the C++ template mechanism (and Qt as well).
My question is: what is the best way to make it work without using ugly hacks like passing function pointers or needing to create a factory implementation for each concrete FtpDelegate's derived class. Maybe there's some clever design pattern I just can't see. Eventually I can rewrite the network mechanism to boost if it is the best option.

It is not possible to create a template Q_OBJECT class (see this and answers).
Instead of using static inheritance, you should use a run-time inheritance, and inject an object inheriting from FtpDelegate class.
It looks like the FtpServer is actually a factory creating connections. From your question, I do not see why it has to be Q_OBJECT class. So you may need to reconsider your design, and simplify that class.
what is the best way to make it work without using ugly hacks like passing function pointers or needing to create a factory implementation for each concrete FtpDelegate's derived class.
The best way may be to have a factory class, which creates instances of FtpDelegate type. But you have so many problems in the posted code, that it is not possible to tell more without knowing all gory details.

Related

Get object instance class name with Qt's meta-object system

I have 3 classes:
class Being : public QObject {
Q_OBJECT
public:
explicit Being(QObject *parent = nullptr);
};
class Animal : public Being {
Q_OBJECT
public:
explicit Animal(QObject *parent = nullptr);
};
class Dog : public Animal {
Q_OBJECT
public:
explicit Dog(QObject *parent = nullptr);
};
Being's implementation is the following:
Being::Being(QObject *parent) : QObject(parent) {
qDebug() << staticMetaObject.className();
}
I have the following code:
Being *pBeing = new Being();
Being *pAnimal = new Animal();
Being *pDog = new Dog();
Question is: is there a way to implement Being's constructor so that I can have access to the actual instance that points to my Being base class so that the log of the above code will be:
Being
Animal
Dog
?
EDIT:
My intention is that I want to be able to have a Animal.txt, Being.txt and Doc.txt that will be processed inside the Being base class. And I need to know, based on the instance's type, whether I need to parse Animal.txt, Being.txt or Doc.txt to get more information.
Does Qt support this? Is there a mechanism I can use to achieve this using C++/Qt? If not, could there be any elegant compromise solution for this?
It is not possible in the constructor of Being because the enclosing object is not constructed yet, therefore metadata about it is not available. However, you can write the initialize method that should be called after the object construction, e.g. with print function:
class Being : public QObject {
Q_OBJECT
public:
explicit Being(QObject *parent = nullptr) { qDebug() << this->metaObject()->className(); } // this will always print "Being"
void initialize() { qDebug() << this->metaObject()->className(); } // this will print the actual class name
};
class Animal : public Being {
Q_OBJECT
public:
explicit Animal(QObject *parent = nullptr) { initialize(); } // you can already use this method in the constructor
};
TEST(xxx, yyy)
{
Being* being = new Being();
Being* animal = new Animal();
being->initialize();
animal->initialize(); // or you can call it later
}
In case initialize method is not good solution, you can always hack it through Being constructor: explicit Being(QString name, QObject* parent = nullptr; and then explicit Animal(QObject *parent = nullptr): Being("Animal") {}, but I think it is less elegant.
My intention is that I want to be able to have a Animal.txt, Being.txt and Doc.txt that will be processed inside the Being base class. And I need to know, based on the instance's type, whether I need to parse Animal.txt, Being.txt or Doc.txt to get more information.
Never let a base class know anything about its subclasses. Ever.
No matter how tempting it might look like, do no do it (even if you find out how).
A class might have hundreds of subclasses. Take for example QObject. Should QObject (or could it possible) know about your reimplementation of QMainWindow?
So, whatever the reason for this design decision is, change it!
Possible solutions
If the process algorithm of the text files is the same, regardless of the subclass, create a base class method to do the processing and call it from the subclasses.
If the algorithm depends on the subclass, make the method abstract, i.e. virtual and withouth implementation (=0), and let the implementation to the subclasses.

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.

Access QList<T> from qml

I want to access a QList from qml.
Here is a sample code
class A;
class B : public QObject {
...
Q_INVOKABLE QQmlListProperty<A> read();
...
private:
QList<A*> lst;
}
I'm using context property to access object of class B in qml.
How can I access the list in qml. Any sample code will be helpful.
You will need to Q_DECLARE_METATYPE(A *) to be able to wrap it in a QVariant for use in QML.
But that's just for referring to and passing it around QML.
If you want to use A in QML as in C++, it will have to inherit QObject and implement properties, slots and such.
You can see how to implement the QQmlListProperty here: http://doc.qt.io/qt-5/qtqml-referenceexamples-properties-example.html
Also, if QObject is too heavy for you and impractical to have a lot of them, you can always use a single QObject derived to work as a controller for a non-QObject but still registered as metatype type.
class A {
public:
int a;
};
Q_DECLARE_METATYPE(A *)
class AProxy : public QObject {
Q_OBJECT
public slots:
int a(QVariant aVar) {
return aVar.value<A *>()->a;
}
void setA(QVariant aVar, int v) {
aVar.value<A *>()->a = v;
}
};
This way you don't have the size overhead and limitations of QObject for every object in the list, and can instead use a single controller to access the data, albeit at lower performance. In your case you could use B to act as both container and controller proxy for A.

Connecting (in an unusual way) signals to slots

I've designed some construction like this:
template<class Ui_Class>
class Base_Dialog : virtual public QDialog, protected Ui_Class
{
protected:
QDialog* caller_;
public:
template<class Implementation>
Base_Dialog(Implementation*const & imp,QDialog *caller,QWidget* parent = nullptr);
};
template<class Ui_Class>
template<class Implementation>
Base_Dialog<Ui_Class>::Base_Dialog(Implementation*const& imp,QDialog *caller,QWidget* parent):
QDialog(parent),
caller_(caller)
{
setupUi(imp);
}
I'm using it like so:
class My_Class : public **Base_Dialog<Ui::My_Class>**
{
Q_OBJECT
public slots:
void display_me()
{/*THIS IS NOT GETTING CONNECTED*/
QMessageBox::warning(this,"Aha!","Aha!");
}
public:
explicit My_Class(QDialog* caller = nullptr,QWidget *parent = nullptr);
};
Line_Counter::Line_Counter(QDialog* caller,QWidget *parent) :
Base_Dialog(this,caller,parent)
{
//setupUi(this);//THIS WORKS BUT I'D RATHER CALL IT FROM Base_Dialog
}
this above construct is suppose to ease and simplify the way of inheriting from QDialog and from Ui class. And this works, except that when slots and signals are introduced in my class the base class for some reason doesn't see them (slots/signals). If I call setupUi in My_Class ctor everything works correctly but I'd prefer to call it in Base_Class. Is there a way to do it?
The constructor for lineCounter should be renamed to My_Class as well, am I right?
The reason for this behavior is that the meta object returned in constructor of Base_Dialog from virtual const QMetaObject * metaObject() const is meta-object for Base_Dialog, as at this stage it is not yet instance of My_Class instance. My_CLass overrides this virtual method (invisibly in Q_OBJECT macro) but only after My_Class constructor code starts to execute - means after Base_Dialog code is finished. Signals and slots internally use meta-objects while connecting, so it seems this way it will not work.
Summarizing - you cannot do it, because constructor of Base_Dialog doesn't know that My_Class instance is being created and therefore cannot have acces to any of it's contents.
Sometimes this problem can be bypassed using CRTP, but in this case I have no idea if it's aplicable. I would rather opt for doing it Qt's way - call setupUi from My_Class constructor.

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.