This is what I have:
class Foo;
class Bar;
class FooBar
{
public:
FooBar( Foo &f, void ( Foo::* signal )( FooBar* ) )
: m_Foo(&f)
, fp_Foo(signal) {};
FooBar( Bar &b, void ( Bar::* signal )( FooBar* ) )
: m_Bar(&b)
, fp_Bar(signal) {};
protected:
void ( Foo::*fp_Foo )( FooBar* );
void ( Bar::*fp_Bar )( FooBar* );
private:
Foo *m_Foo{nullptr};
Bar *m_Bar{nullptr};
};
This is what I want:
class Foo;
class Bar;
class FooBar
{
public:
FooBar( Foo &f, void ( Foo::* signal )( FooBar* ) )
: m_Foo(&f)
, fp(signal) {};
FooBar( Bar &b, void ( Bar::* signal )( FooBar* ) )
: m_Bar(&b)
, fp(signal) {};
protected:
void ( <???>::*fp )( FooBar* ); // Deduplicated
private:
Foo *m_Foo{nullptr};
Bar *m_Bar{nullptr};
};
I want only one set of member function pointers, that can stand in for both Foo
and Bar
.
Is this possible without the use of a template?
Thanks.
To me it seems, that you have a XY problem. That is why I will concentrate on what you actually want to achieve, ie:
I want to add some signals to a QList based class for insertions, changes, and removals. The Q_OBJECT macro however will not work on this:
class CardList : public QList<Card*>
QList
is not a QObject
.
Subclass QObject
and compose the subclass with a list.
Here is a simple example I have written for you to demonstrate the proposed solution:
#include <QObject>
class Card;
class CardList : public QObject // inheritance
{
Q_OBJECT
public:
explicit CardList(QObject *parent = nullptr);
void addCard(Card *); // emit cardAdded here
int cardCount() const;
Card *card(int pos);
bool removeCard(int pos); // emit cardRemoved here
private:
QList<Card *> m_cards; // composition
signals:
void cardAdded(int pos);
void cardRemoved(int pos);
};
Now you can have:
class Game : public QObject
{
...
private:
CardList *m_cards;
...
}
class Player : public QObject
{
...
private:
CardList *m_cards;
...
}
That all being said, maybe a model would suite the needs of your application better.
One option is to use a std::function
in which you store a lambda that calls what you want to call:
#include <functional>
class FooBar {
public:
FooBar(Foo& f, void (Foo::*signal)(FooBar*)) : m_f{[&]{ (f.*signal)(this); }}
{};
FooBar(Bar& b, void (Bar::*signal)(FooBar*)) : m_f{[&]{ (b.*signal)(this); }}
{};
void call() {
m_f();
}
private:
std::function<void()> m_f;
};
If you prefer to have the instance and member function pointer available, you can use a union
to accomplish this. Since you are using C++17, you should however prefer using a std::variant
.
Here's an example of how that could look:
#include <utility>
#include <variant>
class FooBar {
public:
FooBar(Foo& f, void (Foo::*signal)(FooBar*)) : m_fp{std::pair{&f, signal}} {};
FooBar(Bar& b, void (Bar::*signal)(FooBar*)) : m_fp{std::pair{&b, signal}} {};
void call() {
std::visit([this](auto&& fb){
auto&[i, m] = fb;
(i->*m)(this);
}, m_fp);
}
private:
// store both the instance pointer and member pointer in pairs:
std::variant<std::pair<Foo*, void(Foo::*)(FooBar*)>,
std::pair<Bar*, void(Bar::*)(FooBar*)>> m_fp;
};
If you for some reason do not want to use a std::variant
and std::pair
s, just create a similar union
:
struct foopair {
Foo* i;
void (Foo::*m)(FooBar*);
};
struct barpair {
Bar* i;
void (Bar::*m)(FooBar*);
};
union foobaru {
foobaru(Foo& f, void (Foo::*signal)(FooBar*)) : fp{&f, signal} {};
foobaru(Bar& b, void (Bar::*signal)(FooBar*)) : bp{&b, signal} {};
foopair fp;
barpair bp;
};
class FooBar {
public:
FooBar(Foo& f, void (Foo::*signal)(FooBar*)) :
has_foo{true}, m_fb{f, signal} {};
FooBar(Bar& b, void (Bar::*signal)(FooBar*)) :
has_foo{false}, m_fb{b, signal} {};
void call() {
if(has_foo) {
auto&[i, m] = m_fb.fp;
(i->*m)(this);
} else {
auto&[i, m] = m_fb.bp;
(i->*m)(this);
}
}
private:
bool has_foo;
foobaru m_fb;
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.