generalize a c++ method
-
hi,
I'm developing a OPC UA Client application.I wrote c++ code that allows me to subscribe to a variable that is in the server, then every time the variable will change in the server, my application will recive the new value.
this is the subscription code :
QScopedPointer<QOpcUaNode>m_axesPosNode; m_axesPosNode.reset(m_client->node("ns=1;s=theName")); m_axesPosNode->enableMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters(50)); QObject::connect(m_axesPosNode.data(), &QOpcUaNode::attributeUpdated, this, &MachineBackend::axesPosUpdated); // axesPosUpdated will be called every tile value changes on the server
I want to write a method that does the same
void uaSub(QScopedPointer<QOpcUaNode> &node, QString nodeId, void (*theUpdateHandler)(QOpcUa::NodeAttribute, const QVariant &)) { node.reset(m_client->node(nodeId)); node->enableMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters(200)); QObject::connect(node.data(),&QOpcUaNode::attributeUpdated,[=](QOpcUa::NodeAttribute attr,const QVariant &value){ theUpdateHandler(attr,value); }); } // use it uaSub(nIndexNode,"ns=4;s=MAIN.nIndex",*nIndexUpdated);
My problem is *theUpdateHandler must be static (so i can pass it to another function), and because it is static i can not access members of my class in it..
void static nIndexUpdated(QOpcUa::NodeAttribute attr, const QVariant &value){ { Q_UNUSED(attr); qDebug()<< "new value is " << value; //m_url = value.toString(); i cant access Q_properties / signal ... }
Can someone tell me how to handle this please ?
this is more lack of knowledge in c++ than pure qt related question sorry for thatthank you
-
@LeLev See https://stackoverflow.com/questions/14315346/function-pointer-of-a-non-static-member-function-of-a-class
With non-static methods you need an instance of the class to call the method:typedef void (T::*MethodPtr) (); MethodPtr method = &T::MethodA; T *obj = new T(); obj->*method();
-
Hi
Just to be sure i understand.
You think it needs to be static to be used as a parameter
OR
you required it to be a plain c function pointer for the OPC UA to be able to use it later ?
(since you have aYou can use a class member as a parameter
https://www.quantstart.com/articles/Function-Objects-Functors-in-C-Part-1
https://isocpp.org/wiki/faq/pointers-to-membersHowever, the instance having the function should stay alive then and not sure if you want that.
-
hi ! thanks for the answer
@mrjj said in generalize a c++ method:You think it needs to be static to be used as a parameter
yes, I thought that to be able to pass a function A to another function B, A must be static.
thanks for the links i will update the solution here if i can
-
hi,
@fcarney thx , i'm trying to understand how to use std::bind here (i have never used it)
@mrjj the articles are very interesting but i am not able to find the solution that fits my need..please let me show you better my situation, so you can maybe suggest one solution
class UaClient : public QObject { Q_OBJECT public: // CREATES A SUBSCRIPTION, TAKES A METHOD (theUpdateHandler) THAT WILL BE CALLED LATER void uaSub(QScopedPointer<QOpcUaNode> &node, QString nodeId, void (*theUpdateHandler)(QOpcUa::NodeAttribute, const QVariant &)) { node.reset(m_client->node(nodeId)); node->enableMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters(200)); QObject::connect(node.data(),&QOpcUaNode::attributeUpdated,[=](QOpcUa::NodeAttribute attr,const QVariant &value){ theUpdateHandler(attr,value); }); } private : // UPDATE HANDLER , HAS TO ACCESS MEMBER VARIABLES, HAS TO BE PASSED TO uaSub() static void nIndexUpdated(QOpcUa::NodeAttribute attr, const QVariant &value){ // m_someMember = value.toString(); return; } QString m_someMember; }; ... // use the function to create subscriptions and pass the handler functions for every subscription uaSub(nIndexNode,"ns=4;s=MAIN.nIndex",*nIndexUpdated); uaSub(nIndexNode,"ns=4;s=MAIN.nIndex",*speedValueUpdated); uaSub(nIndexNode,"ns=4;s=MAIN.nIndex",*xxxUpdated);
this will work but handler methods (ex : nIndexUpdated ) can't access member variables because they are static.
If i don't mark it static then I have an error in the uaSub method
error : reference to non-static member function must be called invalid use of memeber 'void UaClient::nIndexUpdated(QOpcUa::NodeAttribute,const QVariant&)' (did you forget the '&' ? )
So i still can't figure out how to pass a method to another method (when they both declared in the same class, and they are not static)
-
@LeLev said in generalize a c++ method:
when they both declared in the same class
If they are both in the same class then why do you want to mess around with pointers? I would rather use an enum to specify what I want to execute. You only have 3 different methods in your example, so using pointers will not give you any performance advantages.
-
@mrjj do you mean like this ? this looks good except i will have a huge switch
enum class UpdateHandlers: qint32{ NINDEX = 0, SPEED = 1, XXX = 2 }; void MachineBackend::uaSub1(QScopedPointer<QOpcUaNode> &node, QString nodeId, UpdateHandlers theHandler){ node.reset(m_client->node(nodeId)); node->enableMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters(200)); QObject::connect(node.data(),&QOpcUaNode::attributeUpdated,[=](QOpcUa::NodeAttribute attr,const QVariant &value){ switch (theHandler) { case UpdateHandlers::NINDEX : nIndexUpdated(attr,value);break; case UpdateHandlers::SPEED : nSpeeedUpdated(attr,value);break; case UpdateHandlers::XXX : xxxUpdated(attr,value);break; default: break; } }); return; }
-
edit @mrjj sorry not for you
@jsulm
do you mean this ?enum UpdateHandlers : qint32{ NINDEX, SPEED, XXX }; void MachineBackend::uaSub1(QScopedPointer<QOpcUaNode> &node, QString nodeId, UpdateHandlers theHandler){ node.reset(m_client->node(nodeId)); node->enableMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters(200)); QObject::connect(node.data(),&QOpcUaNode::attributeUpdated,[=](QOpcUa::NodeAttribute attr,const QVariant &value){ switch (theHandler) { case UpdateHandlers::NINDEX : nIndexUpdated(attr,value);break; case UpdateHandlers::SPEED : nSpeeedUpdated(attr,value);break; case UpdateHandlers::XXX : xxxUpdated(attr,value);break; default: break; } }); return; }
-
@LeLev See https://stackoverflow.com/questions/14315346/function-pointer-of-a-non-static-member-function-of-a-class
With non-static methods you need an instance of the class to call the method:typedef void (T::*MethodPtr) (); MethodPtr method = &T::MethodA; T *obj = new T(); obj->*method();
-
@jsulm i think i can not use this last solution, because there is only one instance of this class. it is instantiated in the main.cpp and putted as contextProperty, it is never destroyed and has same life time as my application. I can not create another object of this class
-
@LeLev said in generalize a c++ method:
@jsulm i think i can not use this last solution, because there is only one instance of this class. it is instantiated in the main.cpp and putted as contextProperty, it is never destroyed and has same life time as my application. I can not create another object of this class
ok, when this - in essence - is a singleton, why don't you make the member variable then also static?
-
@J-Hilk said in generalize a c++ method:
why don't you make the member variable then also static?
i have one member variable per subscription,
each member variable has a Q_PROPERTY corresponding to it, so i can use the variable value from QML.is it possible do define Q_PROPERTIES for a static member variable ?
Im trying but getting errors :
moc_machinebackend.cpp:-1: erreur : undefined reference to `MachineBackend::m_url'Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged) public: QString url()const{ return MachineBackend::m_url; } void setUrl(const QString nUrl){ if(MachineBackend::m_url==nUrl)return; MachineBackend::m_url = nUrl; emit urlChanged(nUrl); } private : static QString m_url; signals: void urlChanged(QString url);
-
@LeLev said in generalize a c++ method:
i think i can not use this last solution
Sure you can: you pass the pointer to second method when you call the first method, right? And since both methods are not static you call the first method already on an instance (which is "this" inside the method):
this->*method(); // method is the pointer to the other method
-
@jsulm said in generalize a c++ method:
: you pass the pointer to second method when you call the first method, right?
Yes, but it only works if the
2nd method is static !//first void uaSub(QScopedPointer<QOpcUaNode> &node, QString nodeId , void (*theUpdateHandler)(QOpcUa::NodeAttribute attr,const QVariant &value)){...} // 2nd static void nIndexUpdated(QOpcUa::NodeAttribute attr, const QVariant &value){...} uaSub(nIndexNode,"ns=4;s=MAIN.nIndex",*nIndexUpdated){...} //Here **nIndexUpdated** must be static ! no ?
if it is not static i get :
reference to non-static member function must be called error -
@LeLev Please take a closer look at the snippet I provided before:
typedef void (T::*MethodPtr) (); MethodPtr method = &T::MethodA; T *obj = new T(); obj->*method();
Your syntax is not even correct as you have to use & to get a pointer not *
So in your case something likeclass A { typedef void (A::*MethodPtr) (); void nIndexUpdated() {} void uaSub(..., MethodPtr ptr) { this->*ptr(); } // Somewhere inside class A you call uaSub uaSub(/*params*/, &A::nIndexUpdated); }
-
@jsulm
thank you so much for the help you provide.
Unfortunately i'm so bad, i can't make this workclass MachineBackend : public QObject { typedef void (MachineBackend::*MethodPtr) (); Q_OBJECT void nIndexUpdated(QOpcUa::NodeAttribute attr, const QVariant &value){...} void uaSub2(QScopedPointer<QOpcUaNode>&node, QString nodeId, MethodPtr updateHandlerPtr){ this->*updateHandlerPtr(); // < error here } };
called object type 'MachineBackend ::MethodPtr' (aka 'void (MachineBackend ::*)()' ) is not a function or function pointer