creating hash (or list) of member functions
-
@JonB said:
But I just know it's going to look complicated.... :(
It does look a bit complicated, but it has to deal with variable number of perfectly forwarded arguments and a lot of weird corner cases users come up with. Also it's the standard library, so it's mangled with all those underscore names and defensive programming style, but if you squint a little you'll see it basically returns a class with operator() like I mentioned.
@Chris-Kawa
Thanks. You gotta love hardcore C++, it's so... simple and clean. -
@Chris-Kawa
Thanks. You gotta love hardcore C++, it's so... simple and clean.@JonB said in creating hash (or list) of member functions:
@Chris-Kawa
Thanks. You gotta love hardcore C++, it's so... simple and clean.Now, now...no sarcasm.
But yeah...wouldn't you love to have today's compute resources available for solving the problems of 30 years ago?
-
@mzimmers said in creating hash (or list) of member functions:
but I wonder if you could give me an explanation for the use of the std::bind. The list is just a list of QObjects; how does this "attach" the callback function?
All of this in place of the
typedef void (*clientSlot)()
, with C life used to be so simple :) We can't use that to call a C++ class member function on an instance. So...std::function<void()>
I can be used to call a C++ class member method.
registerClient(T* client, void(T::*cs)())
Here's my client object (of a certain type), and here is the class member function.
clients.push_back(std::bind(cs, client));
Creates and pushes an object which, when invoked, will call
cs(client)
. Which turns out to be the same asclient->cs()
. Which I am just about to question @Chris-Kawa on...!@JonB said in creating hash (or list) of member functions:
All of this in place of the typedef void (*clientSlot)(), with C life used to be so simple :) We can't use that to call a C++ class member function on an instance
who says you can't ?
#include <array> class SomeClass : public QObject { Q_OBJECT typedef void (SomeClass::*SomeClassFunction)(); std::array<SomeClassFunction,3> arrayOfSignalsPointers{&SomeClass::signal1,&SomeClass::signal2, &SomeClass::signal3}; std::array<SomeClassFunction, 3> arrayOfSlotsPointers{&SomeClass::slot1, &SomeClass::slot2, &SomeClass::slot3}; public: explicit SomeClass(QObject *parent = nullptr) : QObject(parent) { QObject::connect(this, &SomeClass::signal1, this, &SomeClass::slot1); QObject::connect(this, &SomeClass::signal2, this, &SomeClass::slot2); QObject::connect(this, &SomeClass::signal3, this, &SomeClass::slot3); qDebug() << "Emit all signals"; for(auto entry : arrayOfSignalsPointers){ (this->*entry)(); } qDebug() << "Call all slots directly"; for(auto entry : arrayOfSlotsPointers){ (this->*entry)(); } } signals: void signal1(); void signal2(); void signal3(); public slots: void slot1(){qDebug() << Q_FUNC_INFO;} void slot2(){qDebug() << Q_FUNC_INFO;} void slot3(){qDebug() << Q_FUNC_INFO;} };
-
@JonB said in creating hash (or list) of member functions:
All of this in place of the typedef void (*clientSlot)(), with C life used to be so simple :) We can't use that to call a C++ class member function on an instance
who says you can't ?
#include <array> class SomeClass : public QObject { Q_OBJECT typedef void (SomeClass::*SomeClassFunction)(); std::array<SomeClassFunction,3> arrayOfSignalsPointers{&SomeClass::signal1,&SomeClass::signal2, &SomeClass::signal3}; std::array<SomeClassFunction, 3> arrayOfSlotsPointers{&SomeClass::slot1, &SomeClass::slot2, &SomeClass::slot3}; public: explicit SomeClass(QObject *parent = nullptr) : QObject(parent) { QObject::connect(this, &SomeClass::signal1, this, &SomeClass::slot1); QObject::connect(this, &SomeClass::signal2, this, &SomeClass::slot2); QObject::connect(this, &SomeClass::signal3, this, &SomeClass::slot3); qDebug() << "Emit all signals"; for(auto entry : arrayOfSignalsPointers){ (this->*entry)(); } qDebug() << "Call all slots directly"; for(auto entry : arrayOfSlotsPointers){ (this->*entry)(); } } signals: void signal1(); void signal2(); void signal3(); public slots: void slot1(){qDebug() << Q_FUNC_INFO;} void slot2(){qDebug() << Q_FUNC_INFO;} void slot3(){qDebug() << Q_FUNC_INFO;} };
@J-Hilk said in creating hash (or list) of member functions:
typedef void (SomeClass::*SomeClassFunction)();
I said that you cannot use
typedef void (*clientSlot)();
, as the OP wrote and one would in C, to call a C++ member function. And you can't: as you show you needClassName::*function
not just plain*function
.Having said that, I was nonetheless not aware that you can use that to get a member function's address and then call
(instance->*memberFunctionPointer)()
. Thank you for clarifying.So.... all this
std::function<>
and particularlystd::bind()
looks like the usual C++ "why would you want to write something simple when you can wrap it up to be complicated"? ;-) -
@J-Hilk said in creating hash (or list) of member functions:
typedef void (SomeClass::*SomeClassFunction)();
I said that you cannot use
typedef void (*clientSlot)();
, as the OP wrote and one would in C, to call a C++ member function. And you can't: as you show you needClassName::*function
not just plain*function
.Having said that, I was nonetheless not aware that you can use that to get a member function's address and then call
(instance->*memberFunctionPointer)()
. Thank you for clarifying.So.... all this
std::function<>
and particularlystd::bind()
looks like the usual C++ "why would you want to write something simple when you can wrap it up to be complicated"? ;-)@JonB said:
So.... all this std::function<> and particularly std::bind() looks like the usual C++ "why would you want to write something simple when you can wrap it up to be complicated"? ;-)
No, it's a way to be generic. To write
typedef void (SomeClass::*SomeClassFunction)()
you have to hardcodeSomeClass
i.e. know it up front. Notice that what @J-Hilk posted will work with one particular class only. I know he just shows how to call a member function from a pointer and that's fine, but it doesn't do much for the original problem.
std::function doesn't care. It just takes any functor you give it and std::bind creates a functor from anything callable you give it. -
@JonB said:
So.... all this std::function<> and particularly std::bind() looks like the usual C++ "why would you want to write something simple when you can wrap it up to be complicated"? ;-)
No, it's a way to be generic. To write
typedef void (SomeClass::*SomeClassFunction)()
you have to hardcodeSomeClass
i.e. know it up front. Notice that what @J-Hilk posted will work with one particular class only. I know he just shows how to call a member function from a pointer and that's fine, but it doesn't do much for the original problem.
std::function doesn't care. It just takes any functor you give it and std::bind creates a functor from anything callable you give it.@Chris-Kawa
Ah yes, I get it.Modern C++ programming is hugely about templates. But, correct me if I am wrong, C++ did not start out with templates, did it?
-
@Chris-Kawa
Ah yes, I get it.Modern C++ programming is hugely about templates. But, correct me if I am wrong, C++ did not start out with templates, did it?
-
@J-Hilk Where "initial commit" at that time would probably be Stroustrup saving it to a big floppy and physically carrying it to the cubicle of his coworkers. Good old times :D
-
@J-Hilk Where "initial commit" at that time would probably be Stroustrup saving it to a big floppy and physically carrying it to the cubicle of his coworkers. Good old times :D
We were beyond floppies by then. The first computer I used had 10.5 inch (I think, unless it was only 8 inch) floppies, https://www.computinghistory.org.uk/det/10247/Nord-ND305-355-Floppy-Disk/ :)